Example #1
0
    def get_permissions(self, trans, encoded_folder_id, **kwd):
        """
        * GET /api/folders/{id}/permissions

        Load all permissions for the given folder id and return it.

        :param  encoded_folder_id:     the encoded id of the folder
        :type   encoded_folder_id:     an encoded id string

        :param  scope:      either 'current' or 'available'
        :type   scope:      string

        :returns:   dictionary with all applicable permissions' values
        :rtype:     dictionary

        :raises: InsufficientPermissionsException
        """
        current_user_roles = trans.get_current_user_roles()
        is_admin = trans.user_is_admin
        decoded_folder_id = self.folder_manager.cut_and_decode(
            trans, encoded_folder_id)
        folder = self.folder_manager.get(trans, decoded_folder_id)

        if not (is_admin or trans.app.security_agent.can_manage_library_item(
                current_user_roles, folder)):
            raise exceptions.InsufficientPermissionsException(
                'You do not have proper permission to access permissions of this folder.'
            )

        scope = kwd.get('scope', None)
        if scope == 'current' or scope is None:
            return self.folder_manager.get_current_roles(trans, folder)
        #  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, folder, query, page, page_limit)
            return_roles = []
            for role in roles:
                role_id = trans.security.encode_id(role.id)
                return_roles.append(
                    dict(id=role_id, 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"
            )
Example #2
0
    def delete(self, trans, id, **kwd):
        """
        DELETE /api/users/{id}
        delete the user with the given ``id``
        Functionality restricted based on admin status

        :param id: the encoded id of the user to delete
        :type  id: str

        :param purge: (optional) if True, purge the user
        :type  purge: bool
        """
        user_to_update = self.user_manager.by_id(self.decode_id(id))
        if trans.user_is_admin:
            purge = util.string_as_bool(kwd.get('purge', False))
            if purge:
                log.debug("Purging user %s", user_to_update)
                self.user_manager.purge(user_to_update)
            else:
                self.user_manager.delete(user_to_update)
        else:
            if trans.user == user_to_update:
                self.user_manager.delete(user_to_update)
            else:
                raise exceptions.InsufficientPermissionsException(
                    'You may only delete your own account.', id=id)
        return self.user_serializer.serialize_to_view(user_to_update,
                                                      view='detailed')
Example #3
0
    def create( self, trans, parent_folder_id, new_folder_name, new_folder_description='' ):
        """
        Create a new folder under the given folder.

        :param  parent_folder_id:       decoded id
        :type   parent_folder_id:       int
        :param  new_folder_name:        name of the new folder
        :type   new_folder_name:        str
        :param  new_folder_description: description of the folder (optional, defaults to empty string)
        :type   new_folder_description: str

        :returns:   the new folder
        :rtype:     LibraryFolder

        :raises: InsufficientPermissionsException
        """
        parent_folder = self.get( trans, parent_folder_id )
        current_user_roles = trans.get_current_user_roles()
        if not ( trans.user_is_admin or trans.app.security_agent.can_add_library_item( current_user_roles, parent_folder ) ):
            raise exceptions.InsufficientPermissionsException( 'You do not have proper permission to create folders under given folder.' )
        new_folder = trans.app.model.LibraryFolder( name=new_folder_name, description=new_folder_description )
        # We are associating the last used genome build with folders, so we will always
        # initialize a new folder with the first dbkey in genome builds list which is currently
        # ?    unspecified (?)
        new_folder.genome_build = trans.app.genome_builds.default_value
        parent_folder.add_folder( new_folder )
        trans.sa_session.add( new_folder )
        trans.sa_session.flush()
        # New folders default to having the same permissions as their parent folder
        trans.app.security_agent.copy_library_permissions( trans, parent_folder, new_folder )
        return new_folder
Example #4
0
 def _get_user(self, trans, id):
     user = self.get_user(trans, id)
     if not user:
         raise exceptions.RequestParameterInvalidException('Invalid user (%s).' % id)
     if user != trans.user and not trans.user_is_admin:
         raise exceptions.InsufficientPermissionsException('Access denied.')
     return user
Example #5
0
 def raw_tool_source(self, trans: GalaxyWebTransaction, id, **kwds):
     """Returns tool source. ``language`` is included in the response header."""
     if not trans.app.config.enable_tool_source_display and not trans.user_is_admin:
         raise exceptions.InsufficientPermissionsException("Only administrators may display tool sources on this Galaxy server.")
     tool = self._get_tool(id, user=trans.user, tool_version=kwds.get('tool_version'))
     trans.response.headers['language'] = tool.tool_source.language
     return tool.tool_source.to_string()
Example #6
0
    def update(self, trans, id, payload, **kwd):
        """
        update( self, trans, id, payload, **kwd )
        * PUT /api/users/{id}
            updates the values for the item with the given ``id``

        :type id: str
        :param id: the encoded id of the item to update
        :type payload: dict
        :param payload: a dictionary of new attribute values

        :rtype: dict
        :returns: an error object if an error occurred or a dictionary containing
            the serialized item after any changes
        """
        current_user = trans.user
        user_to_update = self.user_manager.by_id(self.decode_id(id))

        # only allow updating other users if they're admin
        editing_someone_else = current_user != user_to_update
        is_admin = trans.api_inherit_admin or self.user_manager.is_admin(
            current_user)
        if editing_someone_else and not is_admin:
            raise exceptions.InsufficientPermissionsException(
                'You are not allowed to update that user', id=id)

        self.user_deserializer.deserialize(user_to_update,
                                           payload,
                                           user=current_user,
                                           trans=trans)
        return self.user_serializer.serialize_to_view(user_to_update,
                                                      view='detailed')
Example #7
0
    def get_permissions(
        self,
        trans,
        id: EncodedDatabaseIdField,
        scope: Optional[LibraryPermissionScope] = LibraryPermissionScope.
        current,
        is_library_access: Optional[bool] = False,
        page: Optional[int] = 1,
        page_limit: Optional[int] = 10,
        query: Optional[str] = None,
    ) -> Union[LibraryCurrentPermissions, LibraryAvailablePermissions]:
        """Load all permissions for the given library id and return it.

        :param  id:     the encoded id of the library
        :type   id:     an encoded id string

        :param  scope:      either 'current' or 'available'
        :type   scope:      string

        :param  is_library_access:      indicates whether the roles available for the library access are requested
        :type   is_library_access:      bool

        :returns:   dictionary with all applicable permissions' values
        :rtype:     dictionary

        :raises: InsufficientPermissionsException
        """
        current_user_roles = trans.get_current_user_roles()
        is_admin = trans.user_is_admin
        library = self.library_manager.get(
            trans, trans.security.decode_id(id, object_name='library'))
        if not (is_admin or trans.app.security_agent.can_manage_library_item(
                current_user_roles, library)):
            raise exceptions.InsufficientPermissionsException(
                'You do not have proper permission to access permissions of this library.'
            )

        if scope == LibraryPermissionScope.current or scope is None:
            roles = self.library_manager.get_current_roles(trans, library)
            return LibraryCurrentPermissions.parse_obj(roles)

        #  Return roles that are available to select.
        elif scope == LibraryPermissionScope.available:
            roles, total_roles = trans.app.security_agent.get_valid_roles(
                trans, library, query, page, page_limit, is_library_access)

            return_roles = []
            for role in roles:
                role_id = trans.security.encode_id(role.id)
                return_roles.append(
                    dict(id=role_id, name=role.name, type=role.type))
            return LibraryAvailablePermissions(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"
            )
Example #8
0
    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 as 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:
                role_id = trans.security.encode_id( role.id )
                return_roles.append( dict( id=role_id, 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" )
Example #9
0
    def get_permissions(self, trans, encoded_library_id, **kwd):
        """
        * GET /api/libraries/{id}/permissions

        Load all permissions for the given library id and return it.

        :param  encoded_library_id:     the encoded id of the library
        :type   encoded_library_id:     an encoded id string

        :param  scope:      either 'current' or 'available'
        :type   scope:      string

        :param  is_library_access:      indicates whether the roles available for the library access are requested
        :type   is_library_access:      bool

        :returns:   dictionary with all applicable permissions' values
        :rtype:     dictionary

        :raises: InsufficientPermissionsException
        """
        current_user_roles = trans.get_current_user_roles()
        is_admin = trans.user_is_admin
        library = self.library_manager.get(trans, self.__decode_id(trans, encoded_library_id, 'library'))
        if not (is_admin or trans.app.security_agent.can_manage_library_item(current_user_roles, library)):
            raise exceptions.InsufficientPermissionsException('You do not have proper permission to access permissions of this library.')

        scope = kwd.get('scope', None)
        is_library_access = util.string_as_bool(kwd.get('is_library_access', False))

        if scope == 'current' or scope is None:
            roles = self.library_manager.get_current_roles(trans, library)
            return roles

        #  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, library, query, page, page_limit, is_library_access)

            return_roles = []
            for role in roles:
                role_id = trans.security.encode_id(role.id)
                return_roles.append(dict(id=role_id, 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 create( self, trans, encoded_folder_id, payload, **kwd ):
        """
        * POST /api/folders/{encoded_id}/contents
            create a new library file from an HDA

        :param  encoded_folder_id:      the encoded id of the folder to import dataset(s) to
        :type   encoded_folder_id:      an encoded id string
        :param  payload:    dictionary structure containing:
            :param from_hda_id:         (optional) the id of an accessible HDA to copy into the library
            :type  from_hda_id:         encoded id
            :param ldda_message:        (optional) the new message attribute of the LDDA created
            :type   ldda_message:       str
            :param extended_metadata:   (optional) dub-dictionary containing any extended metadata to associate with the item
            :type  extended_metadata:   dict
        :type   payload:    dict

        :returns:   a dictionary containing the id, name, and 'show' url of the new item
        :rtype:     dict

        :raises:    ObjectAttributeInvalidException,
            InsufficientPermissionsException, ItemAccessibilityException,
            InternalServerError
        """
        encoded_folder_id_16 = self.__decode_library_content_id( trans, encoded_folder_id )
        from_hda_id, ldda_message = ( payload.pop( 'from_hda_id', None ), payload.pop( 'ldda_message', '' ) )
        if ldda_message:
            ldda_message = util.sanitize_html.sanitize_html( ldda_message, 'utf-8' )
        rval = {}
        try:
            decoded_hda_id = self.decode_id( from_hda_id )
            hda = self.hda_manager.get_owned( decoded_hda_id, trans.user, current_history=trans.history )
            hda = self.hda_manager.error_if_uploading( hda )
            folder = self.get_library_folder( trans, encoded_folder_id_16, check_accessible=True )

            library = folder.parent_library
            if library.deleted:
                raise exceptions.ObjectAttributeInvalidException()
            if not self.can_current_user_add_to_library_item( trans, folder ):
                raise exceptions.InsufficientPermissionsException()

            ldda = self.copy_hda_to_library_folder( trans, hda, folder, ldda_message=ldda_message )
            update_time = ldda.update_time.strftime( "%Y-%m-%d %I:%M %p" )
            ldda_dict = ldda.to_dict()
            rval = trans.security.encode_dict_ids( ldda_dict )
            rval['update_time'] = update_time

        except exceptions.ObjectAttributeInvalidException:
            raise exceptions.ObjectAttributeInvalidException( 'You cannot add datasets into deleted library. Undelete it first.' )
        except exceptions.InsufficientPermissionsException:
            raise exceptions.exceptions.InsufficientPermissionsException( 'You do not have proper permissions to add a dataset to a folder with id (%s)' % ( encoded_folder_id ) )
        except Exception as exc:
            # TODO handle exceptions better within the mixins
            if ( ( 'not accessible to the current user' in str( exc ) ) or ( 'You are not allowed to access this dataset' in str( exc ) ) ):
                raise exceptions.ItemAccessibilityException( 'You do not have access to the requested item' )
            else:
                log.exception( exc )
                raise exceptions.InternalServerError( 'An unknown error ocurred. Please try again.' )
        return rval
Example #11
0
    def update_permissions(self, trans, dataset_assoc, **kwd):
        action = kwd.get('action', 'set_permissions')
        if action not in ['remove_restrictions', 'make_private', 'set_permissions']:
            raise exceptions.RequestParameterInvalidException('The mandatory parameter "action" has an invalid value. '
                                                              'Allowed values are: "remove_restrictions", "make_private", "set_permissions"')
        if hasattr(dataset_assoc, "library_dataset_dataset_association"):
            library_dataset = dataset_assoc
            dataset = library_dataset.library_dataset_dataset_association.dataset
        else:
            library_dataset = None
            dataset = dataset_assoc.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.')

        if 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 occurred while making dataset public.')
        elif action == 'make_private':
            if not trans.app.security_agent.dataset_is_private_to_user(trans, 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, dataset):
                # Check again and inform the user if dataset is not private.
                raise exceptions.InternalServerError('An error occurred and the dataset is NOT private.')
        elif action == 'set_permissions':

            def to_role_id(encoded_role_id):
                role_id = base.decode_id(self.app, encoded_role_id)
                return role_id

            def parameters_roles_or_none(role_type):
                encoded_role_ids = kwd.get(role_type, kwd.get(f"{role_type}_ids[]", None))
                if encoded_role_ids is not None:
                    return list(map(to_role_id, encoded_role_ids))
                else:
                    return None

            access_roles = parameters_roles_or_none('access')
            manage_roles = parameters_roles_or_none('manage')
            modify_roles = parameters_roles_or_none('modify')
            role_ids_dict = {
                'DATASET_MANAGE_PERMISSIONS': manage_roles,
                'DATASET_ACCESS': access_roles,
            }
            if library_dataset is not None:
                role_ids_dict["LIBRARY_MODIFY"] = modify_roles

            self._set_permissions(trans, dataset_assoc, role_ids_dict)
Example #12
0
 def detect_datatype(self, trans, dataset_assoc):
     """Sniff and assign the datatype to a given dataset association (ldda or hda)"""
     data = trans.sa_session.query(self.model_class).get(dataset_assoc.id)
     if data.datatype.is_datatype_change_allowed():
         if not data.ok_to_edit_metadata():
             raise exceptions.ItemAccessibilityException('This dataset is currently being used as input or output. You cannot change datatype until the jobs have completed or you have canceled them.')
         else:
             path = data.dataset.file_name
             is_binary = check_binary(path)
             datatype = sniff.guess_ext(path, trans.app.datatypes_registry.sniff_order, is_binary=is_binary)
             trans.app.datatypes_registry.change_datatype(data, datatype)
             trans.sa_session.flush()
             self.set_metadata(trans, dataset_assoc)
     else:
         raise exceptions.InsufficientPermissionsException(f'Changing datatype "{data.extension}" is not allowed.')
    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 as 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())
        nice_size = util.nice_size(
            int(dataset.library_dataset_dataset_association.get_size()))
        rval['file_size'] = nice_size
        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
Example #14
0
    def delete(self, trans, encoded_dataset_id, **kwd):
        """
        DELETE /api/libraries/datasets/{encoded_dataset_id}

        Mark the dataset deleted or undeleted.

        :param  encoded_dataset_id:      the encoded id of the dataset to change
        :type   encoded_dataset_id:      an encoded id string
        :param  undelete:                flag whether to undeleted instead of deleting
        :type   undelete:                bool

        :returns:   dict containing information about the dataset
        :rtype:     dictionary
        """
        undelete = util.string_as_bool(kwd.get('undelete', False))
        library_dataset = self.ld_manager.get(
            trans, managers_base.decode_id(self.app, encoded_dataset_id))
        current_user_roles = trans.get_current_user_roles()
        allowed = trans.app.security_agent.can_modify_library_item(
            current_user_roles, library_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:
            library_dataset.deleted = False
        else:
            library_dataset.deleted = True

        trans.sa_session.add(library_dataset)
        trans.sa_session.flush()

        rval = trans.security.encode_all_ids(library_dataset.to_dict())
        nice_size = util.nice_size(
            int(library_dataset.library_dataset_dataset_association.get_size())
        )
        rval['file_size'] = nice_size
        rval['update_time'] = library_dataset.update_time.strftime(
            "%Y-%m-%d %I:%M %p")
        rval['deleted'] = library_dataset.deleted
        rval['folder_id'] = 'F' + rval['folder_id']
        return rval
Example #15
0
    def check_manageable(self, trans, folder):
        """
        Check whether the user can manage the folder.

        :returns:   the original folder
        :rtype:     LibraryFolder

        :raises: AuthenticationRequired, InsufficientPermissionsException
        """
        if not trans.user:
            raise exceptions.AuthenticationRequired(
                "Must be logged in to manage Galaxy items.", type='error')
        current_user_roles = trans.get_current_user_roles()
        if not trans.app.security_agent.can_manage_library_item(
                current_user_roles, folder):
            raise exceptions.InsufficientPermissionsException(
                "You don't have permissions to manage this folder.",
                type='error')
        else:
            return folder
Example #16
0
class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
    @expose_api_anonymous
    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

        :rtype:     dictionary
        :returns:   detailed dataset information from base controller
        .. seealso:: :attr:`galaxy.web.base.controller.UsesLibraryMixinItems.get_library_dataset`
        """
        try:
            dataset = self.get_library_dataset(trans,
                                               id=id,
                                               check_ownership=False,
                                               check_accessible=True)
        except Exception:
            raise exceptions.ObjectNotFound('Requested dataset was not found.')

        # Build the full path for breadcrumb purposes.
        full_path = self._build_path(trans, dataset.folder)
        dataset_item = (trans.security.encode_id(dataset.id), dataset.name)
        full_path.insert(0, dataset_item)
        full_path = full_path[::-1]

        nice_size = util.nice_size(
            int(dataset.library_dataset_dataset_association.get_size()))

        date_uploaded = dataset.library_dataset_dataset_association.create_time.strftime(
            "%Y-%m-%d %I:%M %p")

        rval = trans.security.encode_all_ids(dataset.to_dict())
        rval['deleted'] = dataset.deleted
        rval['folder_id'] = 'F' + rval['folder_id']
        rval['full_path'] = full_path
        rval['file_size'] = nice_size
        rval['date_uploaded'] = date_uploaded
        return rval

    @expose_api
    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 and available roles
            for a given dataset permission.
        """
        current_user_roles = trans.get_current_user_roles()

        page = kwd.get('page', None)
        if page is not None:
            page = int(page)

        page_limit = kwd.get('page_limit', None)
        if page_limit is not None:
            page_limit = int(page_limit)

        query = kwd.get('q', None)

        if page is None:
            page = 1

        if page_limit is None:
            page_limit = 10

        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))
        library = library_dataset.folder.parent_library
        dataset = library_dataset.library_dataset_dataset_association.dataset

        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 access permissions.')

        roles = trans.app.security_agent.get_valid_dataset_roles(
            trans, dataset, query, page, page_limit)

        total_roles = len(roles)
        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)
Example #17
0
            of the undelete flag (if present).
        """
        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
Example #18
0
    def load(self, trans, payload=None, **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/[email protected]/{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   payload: dictionary structure containing:
            :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 from
            :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
        :type   dictionary
        :returns:   dict containing information about the created upload job
        :rtype:     dictionary
        :raises: RequestParameterMissingException, AdminRequiredException, ConfigDoesNotAllowException, RequestParameterInvalidException
                    InsufficientPermissionsException, ObjectNotFound
        """
        if payload:
            kwd.update(payload)
        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.populate_state(trans, tool.inputs, kwd, state.inputs)
        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)
        # 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', kwd,
                                        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', kwd, 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', kwd, 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_params = {}
        job_params['link_data_only'] = dumps(
            kwd.get('link_data_only', 'copy_files'))
        job_params['uuid'] = dumps(kwd.get('uuid', None))
        job, output = upload_common.create_job(trans,
                                               tool_params,
                                               tool,
                                               json_file_path,
                                               data_list,
                                               folder=folder,
                                               job_params=job_params)
        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
Example #19
0
    def set_permissions(self, trans, encoded_library_id, payload=None, **kwd):
        """
        *POST /api/libraries/{encoded_library_id}/permissions
            Set permissions of the given library to the given role ids.

        :param  encoded_library_id:      the encoded id of the library to set the permissions of
        :type   encoded_library_id:      an encoded id string
        :param   payload: dictionary structure containing:
            :param  action:            (required) describes what action should be performed
                                       available actions: remove_restrictions, set_permissions
            :type   action:            str
            :param  access_ids[]:      list of Role.id defining roles that should have access permission on the library
            :type   access_ids[]:      string or list
            :param  add_ids[]:         list of Role.id defining roles that should have add item permission on the library
            :type   add_ids[]:         string or list
            :param  manage_ids[]:      list of Role.id defining roles that should have manage permission on the library
            :type   manage_ids[]:      string or list
            :param  modify_ids[]:      list of Role.id defining roles that should have modify permission on the library
            :type   modify_ids[]:      string or list
        :type:      dictionary
        :returns:   dict of current roles for all available permission types
        :rtype:     dictionary
        :raises: RequestParameterInvalidException, InsufficientPermissionsException, InternalServerError
                    RequestParameterMissingException
        """
        if payload:
            kwd.update(payload)
        is_admin = trans.user_is_admin()
        current_user_roles = trans.get_current_user_roles()
        library = self.library_manager.get(
            trans, self.__decode_id(trans, encoded_library_id, 'library'))

        if not (is_admin or trans.app.security_agent.can_manage_library_item(
                current_user_roles, library)):
            raise exceptions.InsufficientPermissionsException(
                'You do not have proper permission to modify permissions of this library.'
            )

        new_access_roles_ids = util.listify(kwd.get('access_ids[]', None))
        new_add_roles_ids = util.listify(kwd.get('add_ids[]', None))
        new_manage_roles_ids = util.listify(kwd.get('manage_ids[]', None))
        new_modify_roles_ids = util.listify(kwd.get('modify_ids[]', None))

        action = kwd.get('action', None)
        if action is None:
            if payload is not None:
                return self.set_permissions_old(trans, library, payload, **kwd)
            else:
                raise exceptions.RequestParameterMissingException(
                    'The mandatory parameter "action" is missing.')
        elif action == 'remove_restrictions':
            is_public = self.library_manager.make_public(trans, library)
            if not is_public:
                raise exceptions.InternalServerError(
                    'An error occured while making library public.')
        elif action == 'set_permissions':

            # ACCESS LIBRARY ROLES
            valid_access_roles = []
            invalid_access_roles_names = []
            for role_id in new_access_roles_ids:
                role = self.role_manager.get(
                    trans, self.__decode_id(trans, role_id, 'role'))
                valid_roles, total_roles = trans.app.security_agent.get_valid_roles(
                    trans, library, is_library_access=True)
                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 library access permission: "
                    + str(invalid_access_roles_names))

            # ADD TO LIBRARY ROLES
            valid_add_roles = []
            invalid_add_roles_names = []
            for role_id in new_add_roles_ids:
                role = self.role_manager.get(
                    trans, self.__decode_id(trans, role_id, 'role'))
                valid_roles, total_roles = trans.app.security_agent.get_valid_roles(
                    trans, library)
                if role in valid_roles:
                    valid_add_roles.append(role)
                else:
                    invalid_add_roles_names.append(role_id)
            if len(invalid_add_roles_names) > 0:
                log.warning(
                    "The following roles could not be added to the add library item permission: "
                    + str(invalid_add_roles_names))

            # MANAGE LIBRARY ROLES
            valid_manage_roles = []
            invalid_manage_roles_names = []
            for role_id in new_manage_roles_ids:
                role = self.role_manager.get(
                    trans, self.__decode_id(trans, role_id, 'role'))
                valid_roles, total_roles = trans.app.security_agent.get_valid_roles(
                    trans, library)
                if role in valid_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 manage library permission: "
                    + str(invalid_manage_roles_names))

            # MODIFY LIBRARY ROLES
            valid_modify_roles = []
            invalid_modify_roles_names = []
            for role_id in new_modify_roles_ids:
                role = self.role_manager.get(
                    trans, self.__decode_id(trans, role_id, 'role'))
                valid_roles, total_roles = trans.app.security_agent.get_valid_roles(
                    trans, library)
                if role in valid_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 modify library permission: "
                    + str(invalid_modify_roles_names))

            permissions = {
                trans.app.security_agent.permitted_actions.LIBRARY_ACCESS:
                valid_access_roles
            }
            permissions.update({
                trans.app.security_agent.permitted_actions.LIBRARY_ADD:
                valid_add_roles
            })
            permissions.update({
                trans.app.security_agent.permitted_actions.LIBRARY_MANAGE:
                valid_manage_roles
            })
            permissions.update({
                trans.app.security_agent.permitted_actions.LIBRARY_MODIFY:
                valid_modify_roles
            })

            trans.app.security_agent.set_all_library_permissions(
                trans, library, permissions)
            trans.sa_session.refresh(library)
            # Copy the permissions to the root folder
            trans.app.security_agent.copy_library_permissions(
                trans, library, library.root_folder)
        else:
            raise exceptions.RequestParameterInvalidException(
                'The mandatory parameter "action" has an invalid value.'
                'Allowed values are: "remove_restrictions", set_permissions"')
        roles = self.library_manager.get_current_roles(trans, library)
        return roles
Example #20
0
        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:
Example #21
0
    def set_permissions( self, trans, encoded_folder_id, **kwd ):
        """
        def set_permissions( self, trans, encoded_folder_id, **kwd ):
            *POST /api/folders/{encoded_folder_id}/permissions

        :param  encoded_folder_id:      the encoded id of the folder to set the permissions of
        :type   encoded_folder_id:      an encoded id string      

        :param  action:     (required) describes what action should be performed
                            available actions: set_permissions
        :type   action:     string        

        :param  add_ids[]:         list of Role.id defining roles that should have add item permission on the folder
        :type   add_ids[]:         string or list  
        :param  manage_ids[]:      list of Role.id defining roles that should have manage permission on the folder
        :type   manage_ids[]:      string or list  
        :param  modify_ids[]:      list of Role.id defining roles that should have modify permission on the folder
        :type   modify_ids[]:      string or list          

        :rtype:     dictionary
        :returns:   dict of current roles for all available permission types.

        :raises: RequestParameterInvalidException, ObjectNotFound, InsufficientPermissionsException, InternalServerError
                    RequestParameterMissingException
        """
        is_admin = trans.user_is_admin()
        current_user_roles = trans.get_current_user_roles()

        decoded_folder_id = self.folder_manager.decode_folder_id( trans, self.folder_manager.cut_the_prefix( encoded_folder_id ) )
        folder = self.folder_manager.get( trans, decoded_folder_id )
        if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, folder ) ):
            raise exceptions.InsufficientPermissionsException( 'You do not have proper permission to modify permissions of this folder.' )

        new_add_roles_ids = util.listify( kwd.get( 'add_ids[]', None ) )
        new_manage_roles_ids = util.listify( kwd.get( 'manage_ids[]', None ) )
        new_modify_roles_ids = util.listify( 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 == 'set_permissions':

            # ADD TO LIBRARY ROLES
            valid_add_roles = []
            invalid_add_roles_names = []
            for role_id in new_add_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, folder )
                if role in valid_roles:
                    valid_add_roles.append( role )
                else:
                    invalid_add_roles_names.append( role_id )
            if len( invalid_add_roles_names ) > 0:
                log.warning( "The following roles could not be added to the add library item permission: " + str( invalid_add_roles_names ) ) 
            
            # MANAGE FOLDER ROLES
            valid_manage_roles = []
            invalid_manage_roles_names = []
            for role_id in new_manage_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, folder )
                if role in valid_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 manage folder permission: " + str( invalid_manage_roles_names ) ) 
            
            # MODIFY FOLDER ROLES
            valid_modify_roles = []
            invalid_modify_roles_names = []
            for role_id in new_modify_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, folder )
                if role in valid_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 modify folder permission: " + str( invalid_modify_roles_names ) )                

            permissions = { trans.app.security_agent.permitted_actions.LIBRARY_ADD : valid_add_roles }
            permissions.update( { trans.app.security_agent.permitted_actions.LIBRARY_MANAGE : valid_manage_roles } )
            permissions.update( { trans.app.security_agent.permitted_actions.LIBRARY_MODIFY : valid_modify_roles } )

            trans.app.security_agent.set_all_library_permissions( trans, folder, permissions )
        else:
            raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.' 
                                'Allowed values are: "set_permissions"' )
        return self.folder_manager.get_current_roles( trans, folder )
Example #22
0
    def update_permissions(self, trans, encoded_dataset_id, payload=None, **kwd):
        """
        POST /api/libraries/datasets/{encoded_dataset_id}/permissions

        Set permissions of the given library dataset to the given role ids.

        :param  encoded_dataset_id:      the encoded id of the dataset to update permissions of
        :type   encoded_dataset_id:      an encoded id string
        :param   payload: dictionary structure containing:

            :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.id defining roles that should have access permission on the dataset
            :type   access_ids[]:      string or list
            :param  manage_ids[]:      list of Role.id defining roles that should have manage permission on the dataset
            :type   manage_ids[]:      string or list
            :param  modify_ids[]:      list of Role.id defining roles that should have modify permission on the library dataset item
            :type   modify_ids[]:      string or list

        :type:      dictionary

        :returns:   dict of current roles for all available permission types
        :rtype:     dictionary

        :raises: RequestParameterInvalidException, ObjectNotFound, InsufficientPermissionsException, InternalServerError
                    RequestParameterMissingException
        """
        if payload:
            kwd.update(payload)
        action = kwd.get('action', None)
        if action not in ['remove_restrictions', 'make_private', 'set_permissions']:
            raise exceptions.RequestParameterInvalidException('The mandatory parameter "action" has an invalid value. '
                                                              'Allowed values are: "remove_restrictions", "make_private", "set_permissions"')
        library_dataset = self.ld_manager.get(trans, managers_base.decode_id(self.app, encoded_dataset_id))
        # Some permissions are attached directly to the underlying dataset.
        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 = util.listify(kwd.get('access_ids[]', None))
        new_manage_roles_ids = util.listify(kwd.get('manage_ids[]', None))
        new_modify_roles_ids = util.listify(kwd.get('modify_ids[]', None))
        if 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 occurred while making dataset public.')
        elif action == 'make_private':
            if not trans.app.security_agent.dataset_is_private_to_user(trans, 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, dataset):
                # Check again and inform the user if dataset is not private.
                raise exceptions.InternalServerError('An error occurred and the dataset is NOT private.')
        elif action == 'set_permissions':
            # ACCESS DATASET ROLES
            valid_access_roles = []
            invalid_access_roles_ids = []
            valid_roles_for_dataset, total_roles = trans.app.security_agent.get_valid_roles(trans, dataset)
            if new_access_roles_ids is None:
                trans.app.security_agent.make_dataset_public(dataset)
            else:
                for role_id in new_access_roles_ids:
                    role = self.role_manager.get(trans, managers_base.decode_id(self.app, role_id))
                    if role in valid_roles_for_dataset:
                        valid_access_roles.append(role)
                    else:
                        invalid_access_roles_ids.append(role_id)
                if len(invalid_access_roles_ids) > 0:
                    log.warning(f"The following roles could not be added to the dataset access permission: {str(invalid_access_roles_ids)}")

                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_ids = []
            new_manage_roles_ids = util.listify(new_manage_roles_ids)
            for role_id in new_manage_roles_ids:
                role = self.role_manager.get(trans, managers_base.decode_id(self.app, role_id))
                if role in valid_roles_for_dataset:
                    valid_manage_roles.append(role)
                else:
                    invalid_manage_roles_ids.append(role_id)
            if len(invalid_manage_roles_ids) > 0:
                log.warning(f"The following roles could not be added to the dataset manage permission: {str(invalid_manage_roles_ids)}")
            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_ids = []
            new_modify_roles_ids = util.listify(new_modify_roles_ids)
            for role_id in new_modify_roles_ids:
                role = self.role_manager.get(trans, managers_base.decode_id(self.app, role_id))
                if role in valid_roles_for_dataset:
                    valid_modify_roles.append(role)
                else:
                    invalid_modify_roles_ids.append(role_id)
            if len(invalid_modify_roles_ids) > 0:
                log.warning(f"The following roles could not be added to the dataset modify permission: {str(invalid_modify_roles_ids)}")
            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)
        return self._get_current_roles(trans, library_dataset)
Example #23
0
    def load(self, trans, **kwd):
        """
        Load dataset from the given source into the library.

        :param  encoded_folder_id:      the encoded id of the folder to import dataset to
        :type   encoded_folder_id:      an encoded id string
        :param  source:                 source of the dataset to be loaded
        :type   source:                 str
        :param  link_data:              flag whether to link the dataset to data or copy it to Galaxy
        :type   link_data:              bool
        :param  preserve_dirs:          flag whether to preserver directory structure when importing dir
        :type   preserve_dirs:          bool
        """

        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.'
                )
            user_base_dir = trans.app.config.library_import_dir

        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)
            # path_to_root_import_folder = None
            if not path.lower().startswith(full_dir.lower()):
                # path_to_root_import_folder = path
                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_name, input in tool.inputs.iteritems():
            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
        params = util.Params(kwd)
        # user wants to import one file only
        if source == "userdir_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 (admins only)
        if source == "admin_path":
            # 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
Example #24
0
    def load(self, trans, payload=None, **kwd):
        """
        POST /api/libraries/datasets

        Load dataset(s) from the given source into the library.

        :param   payload: dictionary structure containing:
            :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 from. 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/[email protected]/{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

            :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
            :param  tag_using_filenames:    flag whether to generate dataset tags from filenames
            :type   tag_using_filenames:    bool

        :type   dictionary

        :returns:   dict containing information about the created upload job
        :rtype:     dictionary

        :raises: RequestParameterMissingException, AdminRequiredException, ConfigDoesNotAllowException, RequestParameterInvalidException
                    InsufficientPermissionsException, ObjectNotFound
        """
        if payload:
            kwd.update(payload)
        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'
        kwd['tag_using_filenames'] = util.string_as_bool(kwd.get('tag_using_filenames', None))
        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 attribute encoded_folder_id is missing.')
        path = kwd.get('path', None)
        if path is None:
            raise exceptions.RequestParameterMissingException('The required attribute path is missing.')
        if not isinstance(path, str):
            raise exceptions.RequestParameterInvalidException('The required attribute path is not String.')

        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". ')
        elif 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
            if not safe_relpath(path):
                # admins shouldn't be able to explicitly specify a path outside server_dir, but symlinks are allowed.
                # the reasoning here is that galaxy admins may not have direct filesystem access or can only access
                # library_import_dir via FTP (which cannot create symlinks), and may rely on sysadmins to set up the
                # import directory. if they have filesystem access, all bets are off.
                raise exceptions.RequestParameterInvalidException('The given path is invalid.')
            path = os.path.join(import_base_dir, path)
        elif source in ['userdir_file', 'userdir_folder']:
            username = trans.user.username if trans.app.config.user_library_import_check_permissions else None
            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 safe_contains(full_dir, path, allowlist=trans.app.config.user_library_import_symlink_allowlist):
                # the path is a symlink outside the user dir
                path = os.path.join(full_dir, path)
                log.error('User attempted to import a path that resolves to a path outside of their import dir: %s -> %s', path, os.path.realpath(path))
                raise exceptions.RequestParameterInvalidException('The given path is invalid.')
            if trans.app.config.user_library_import_check_permissions and not full_path_permission_for_user(full_dir, path, username):
                log.error('User attempted to import a path that resolves to a path outside of their import dir: '
                        '%s -> %s and cannot be read by them.', path, os.path.realpath(path))
                raise exceptions.RequestParameterInvalidException('The given path is invalid.')
            path = os.path.join(full_dir, path)
            if unsafe_walk(path, allowlist=[full_dir] + trans.app.config.user_library_import_symlink_allowlist, username=username):
                # the path is a dir and contains files that symlink outside the user dir
                error = 'User attempted to import a path that resolves to a path outside of their import dir: {} -> {}'.format(
                    path, os.path.realpath(path)
                )
                if trans.app.config.user_library_import_check_permissions:
                    error += ' or is not readable for them.'
                log.error(error)
                raise exceptions.RequestParameterInvalidException('The given path is invalid.')
            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.')
        elif 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)
        populate_state(trans, tool.inputs, kwd, state.inputs)
        tool_params = state.inputs
        dataset_upload_inputs = []
        for input in tool.inputs.values():
            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)
        # user wants to import one file only
        elif source in ["userdir_file", "importdir_file"]:
            file = os.path.abspath(path)
            abspath_datasets.append(self._make_library_uploaded_dataset(
                trans, kwd, os.path.basename(file), file, 'server_dir', library_bunch))
        # user wants to import whole folder
        elif source == "userdir_folder":
            uploaded_datasets_bunch = self._get_path_paste_uploaded_datasets(
                trans, kwd, 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 = self._get_path_paste_uploaded_datasets(
                trans, kwd, 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_params = {}
        job_params['link_data_only'] = dumps(kwd.get('link_data_only', 'copy_files'))
        job_params['uuid'] = dumps(kwd.get('uuid', None))
        job, output = upload_common.create_job(trans, tool_params, tool, json_file_path, data_list, folder=folder, job_params=job_params)
        trans.app.job_manager.enqueue(job, tool=tool)
        job_dict = job.to_dict()
        job_dict['id'] = trans.security.encode_id(job_dict['id'])
        return job_dict