Ejemplo n.º 1
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 occured 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 occured 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("%s_ids[]" % role_type, 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)
Ejemplo n.º 2
0
    def add_custom_builds(self, trans, id, key, payload={}, **kwd):
        """
        PUT /api/users/{id}/custom_builds/{key}
        Add new custom build.

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

        :param id: custom build key
        :type  id: str

        :param payload: data with new build details
        :type  payload: dict
        """
        user = self._get_user(trans, id)
        dbkeys = json.loads(user.preferences['dbkeys']
                            ) if 'dbkeys' in user.preferences else {}
        name = payload.get('name')
        len_type = payload.get('len|type')
        len_value = payload.get('len|value')
        if len_type not in ['file', 'fasta', 'text'] or not len_value:
            raise exceptions.RequestParameterInvalidException(
                'Please specify a valid data source type.')
        if not name or not key:
            raise exceptions.RequestParameterMissingException(
                'You must specify values for all the fields.')
        elif key in dbkeys:
            raise exceptions.DuplicatedIdentifierException(
                'There is already a custom build with that key. Delete it first if you want to replace it.'
            )
        else:
            # Have everything needed; create new build.
            build_dict = {'name': name}
            if len_type in ['text', 'file']:
                # Create new len file
                new_len = trans.app.model.HistoryDatasetAssociation(
                    extension='len',
                    create_dataset=True,
                    sa_session=trans.sa_session)
                trans.sa_session.add(new_len)
                new_len.name = name
                new_len.visible = False
                new_len.state = trans.app.model.Job.states.OK
                new_len.info = 'custom build .len file'
                try:
                    trans.app.object_store.create(new_len.dataset)
                except ObjectInvalid:
                    raise exceptions.InternalServerError(
                        'Unable to create output dataset: object store is full.'
                    )
                trans.sa_session.flush()
                counter = 0
                lines_skipped = 0
                with open(new_len.file_name, 'w') as f:
                    # LEN files have format:
                    #   <chrom_name><tab><chrom_length>
                    for line in len_value.split('\n'):
                        # Splits at the last whitespace in the line
                        lst = line.strip().rsplit(None, 1)
                        if not lst or len(lst) < 2:
                            lines_skipped += 1
                            continue
                        chrom, length = lst[0], lst[1]
                        try:
                            length = int(length)
                        except ValueError:
                            lines_skipped += 1
                            continue
                        if chrom != escape(chrom):
                            build_dict[
                                'message'] = 'Invalid chromosome(s) with HTML detected and skipped.'
                            lines_skipped += 1
                            continue
                        counter += 1
                        f.write('%s\t%s\n' % (chrom, length))
                build_dict['len'] = new_len.id
                build_dict['count'] = counter
            else:
                build_dict['fasta'] = trans.security.decode_id(len_value)
                dataset = trans.sa_session.query(
                    trans.app.model.HistoryDatasetAssociation).get(
                        build_dict['fasta'])
                try:
                    new_len = dataset.get_converted_dataset(trans, 'len')
                    new_linecount = new_len.get_converted_dataset(
                        trans, 'linecount')
                    build_dict['len'] = new_len.id
                    build_dict['linecount'] = new_linecount.id
                except Exception:
                    raise exceptions.ToolExecutionError(
                        'Failed to convert dataset.')
            dbkeys[key] = build_dict
            user.preferences['dbkeys'] = json.dumps(dbkeys)
            trans.sa_session.flush()
            return build_dict
Ejemplo n.º 3
0
    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))
Ejemplo n.º 4
0
            raise exceptions.InsufficientPermissionsException(
                'You do not have proper permissions to manage permissions on this dataset.'
            )

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

        action = kwd.get('action', None)
        if action is None:
            raise exceptions.RequestParameterMissingException(
                'The mandatory parameter "action" is missing.')
        elif action == 'remove_restrictions':
            trans.app.security_agent.make_dataset_public(dataset)
            if not trans.app.security_agent.dataset_is_public(dataset):
                raise exceptions.InternalServerError(
                    'An error occured while making dataset public.')
        elif action == 'make_private':
            trans.app.security_agent.make_dataset_public(dataset)
            private_role = trans.app.security_agent.get_private_user_role(
                trans.user)
            dp = trans.app.model.DatasetPermissions(
                trans.app.security_agent.permitted_actions.DATASET_ACCESS.
                action, dataset, private_role)
            trans.sa_session.add(dp)
            trans.sa_session.flush()
            if not trans.app.security_agent.dataset_is_private_to_user(
                    trans, library_dataset):
                raise exceptions.InternalServerError(
                    'An error occured while making dataset private.')
        elif action == 'set_permissions':
Ejemplo n.º 5
0
    def download(self, trans, format, **kwd):
        """
        GET /api/libraries/datasets/download/{format}
        POST /api/libraries/datasets/download/{format}

        Download requested datasets (identified by encoded IDs) in requested format.

        example: ``GET localhost:8080/api/libraries/datasets/download/tbz?ld_ids%255B%255D=a0d84b45643a2678&ld_ids%255B%255D=fe38c84dcd46c828``

        .. note:: supported format values are: 'zip', 'tgz', 'tbz', 'uncompressed'

        :param  format:      string representing requested archive format
        :type   format:      string
        :param  ld_ids[]:      an array of encoded dataset ids
        :type   ld_ids[]:      an array
        :param  folder_ids[]:      an array of encoded folder ids
        :type   folder_ids[]:      an array

        :returns: either archive with the requested datasets packed inside or a single uncompressed dataset
        :rtype:   file

        :raises: MessageException, ItemDeletionException, ItemAccessibilityException, HTTPBadRequest, OSError, IOError, ObjectNotFound
        """
        library_datasets = []
        datasets_to_download = kwd.get('ld_ids%5B%5D', None)
        if datasets_to_download is None:
            datasets_to_download = kwd.get('ld_ids', None)
        if datasets_to_download is not None:
            datasets_to_download = util.listify(datasets_to_download)
            for dataset_id in datasets_to_download:
                try:
                    library_dataset = self.get_library_dataset(trans, id=dataset_id, check_ownership=False, check_accessible=True)
                    library_datasets.append(library_dataset)
                except HTTPBadRequest:
                    raise exceptions.RequestParameterInvalidException('Bad Request.')
                except HTTPInternalServerError:
                    raise exceptions.InternalServerError('Internal error.')
                except Exception as e:
                    raise exceptions.InternalServerError('Unknown error.' + util.unicodify(e))

        folders_to_download = kwd.get('folder_ids%5B%5D', None)
        if folders_to_download is None:
            folders_to_download = kwd.get('folder_ids', None)
        if folders_to_download is not None:
            folders_to_download = util.listify(folders_to_download)

            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:
                        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:
                        rval.append(ld)
                return rval

            for encoded_folder_id in folders_to_download:
                folder_id = self.folder_manager.cut_and_decode(trans, encoded_folder_id)
                folder = self.folder_manager.get(trans, folder_id)
                library_datasets.extend(traverse(folder))

        if not library_datasets:
            raise exceptions.RequestParameterMissingException('Request has to contain a list of dataset ids or folder ids to download.')

        if format in ['zip', 'tgz', 'tbz']:
            # error = False
            killme = string.punctuation + string.whitespace
            trantab = maketrans(killme, '_' * len(killme))
            try:
                outext = 'zip'
                if format == 'zip':
                    # Can't use mkstemp - the file must not exist first
                    tmpd = tempfile.mkdtemp()
                    util.umask_fix_perms(tmpd, trans.app.config.umask, 0o777, self.app.config.gid)
                    tmpf = os.path.join(tmpd, 'library_download.' + format)
                    if trans.app.config.upstream_gzip:
                        archive = zipfile.ZipFile(tmpf, 'w', zipfile.ZIP_STORED, True)
                    else:
                        archive = zipfile.ZipFile(tmpf, 'w', zipfile.ZIP_DEFLATED, True)
                    archive.add = lambda x, y: archive.write(x, y.encode('CP437'))
                elif format == 'tgz':
                    if trans.app.config.upstream_gzip:
                        archive = StreamBall('w|')
                        outext = 'tar'
                    else:
                        archive = StreamBall('w|gz')
                        outext = 'tgz'
                elif format == 'tbz':
                    archive = StreamBall('w|bz2')
                    outext = 'tbz2'
            except (OSError, zipfile.BadZipfile):
                log.exception("Unable to create archive for download")
                raise exceptions.InternalServerError("Unable to create archive for download.")
            except Exception:
                log.exception("Unexpected error in create archive for download")
                raise exceptions.InternalServerError("Unable to create archive for download.")
            composite_extensions = trans.app.datatypes_registry.get_composite_extensions()
            seen = []
            for ld in library_datasets:
                ldda = ld.library_dataset_dataset_association
                ext = ldda.extension
                is_composite = ext in composite_extensions
                path = ""
                parent_folder = ldda.library_dataset.folder
                while parent_folder is not None:
                    # Exclude the now-hidden "root folder"
                    if parent_folder.parent is None:
                        path = os.path.join(parent_folder.library_root[0].name, path)
                        break
                    path = os.path.join(parent_folder.name, path)
                    parent_folder = parent_folder.parent
                path += ldda.name
                while path in seen:
                    path += '_'
                path = "{path}.{extension}".format(path=path, extension=ldda.extension)
                seen.append(path)
                zpath = os.path.split(path)[-1]  # comes as base_name/fname
                outfname, zpathext = os.path.splitext(zpath)

                if is_composite:
                    # need to add all the components from the extra_files_path to the zip
                    if zpathext == '':
                        zpath = '%s.html' % zpath  # fake the real nature of the html file
                    try:
                        if format == 'zip':
                            archive.add(ldda.dataset.file_name, zpath)  # add the primary of a composite set
                        else:
                            archive.add(ldda.dataset.file_name, zpath, check_file=True)  # add the primary of a composite set
                    except IOError:
                        log.exception("Unable to add composite parent %s to temporary library download archive", ldda.dataset.file_name)
                        raise exceptions.InternalServerError("Unable to create archive for download.")
                    except ObjectNotFound:
                        log.exception("Requested dataset %s does not exist on the host.", ldda.dataset.file_name)
                        raise exceptions.ObjectNotFound("Requested dataset not found. ")
                    except Exception as e:
                        log.exception("Unable to add composite parent %s to temporary library download archive", ldda.dataset.file_name)
                        raise exceptions.InternalServerError("Unable to add composite parent to temporary library download archive. " + util.unicodify(e))

                    flist = glob.glob(os.path.join(ldda.dataset.extra_files_path, '*.*'))  # glob returns full paths
                    for fpath in flist:
                        efp, fname = os.path.split(fpath)
                        if fname > '':
                            fname = fname.translate(trantab)
                        try:
                            if format == 'zip':
                                archive.add(fpath, fname)
                            else:
                                archive.add(fpath, fname, check_file=True)
                        except IOError:
                            log.exception("Unable to add %s to temporary library download archive %s", fname, outfname)
                            raise exceptions.InternalServerError("Unable to create archive for download.")
                        except ObjectNotFound:
                            log.exception("Requested dataset %s does not exist on the host.", fpath)
                            raise exceptions.ObjectNotFound("Requested dataset not found.")
                        except Exception as e:
                            log.exception("Unable to add %s to temporary library download archive %s", fname, outfname)
                            raise exceptions.InternalServerError("Unable to add dataset to temporary library download archive . " + util.unicodify(e))
                else:
                    try:
                        if format == 'zip':
                            archive.add(ldda.dataset.file_name, path)
                        else:
                            archive.add(ldda.dataset.file_name, path, check_file=True)
                    except IOError:
                        log.exception("Unable to write %s to temporary library download archive", ldda.dataset.file_name)
                        raise exceptions.InternalServerError("Unable to create archive for download")
                    except ObjectNotFound:
                        log.exception("Requested dataset %s does not exist on the host.", ldda.dataset.file_name)
                        raise exceptions.ObjectNotFound("Requested dataset not found.")
                    except Exception as e:
                        log.exception("Unable to add %s to temporary library download archive %s", ldda.dataset.file_name, outfname)
                        raise exceptions.InternalServerError("Unknown error. " + util.unicodify(e))
            lname = 'selected_dataset'
            fname = lname.replace(' ', '_') + '_files'
            if format == 'zip':
                archive.close()
                trans.response.set_content_type("application/octet-stream")
                trans.response.headers["Content-Disposition"] = 'attachment; filename="%s.%s"' % (fname, outext)
                archive = util.streamball.ZipBall(tmpf, tmpd)
                archive.wsgi_status = trans.response.wsgi_status()
                archive.wsgi_headeritems = trans.response.wsgi_headeritems()
                return archive.stream
            else:
                trans.response.set_content_type("application/x-tar")
                trans.response.headers["Content-Disposition"] = 'attachment; filename="%s.%s"' % (fname, outext)
                archive.wsgi_status = trans.response.wsgi_status()
                archive.wsgi_headeritems = trans.response.wsgi_headeritems()
                return archive.stream
        elif format == 'uncompressed':
            if len(library_datasets) != 1:
                raise exceptions.RequestParameterInvalidException("You can download only one uncompressed file at once.")
            else:
                single_ld = library_datasets[0]
                ldda = single_ld.library_dataset_dataset_association
                dataset = ldda.dataset
                fStat = os.stat(dataset.file_name)
                trans.response.set_content_type(ldda.get_mime())
                trans.response.headers['Content-Length'] = int(fStat.st_size)
                fname = "{path}.{extension}".format(path=ldda.name, extension=ldda.extension)
                fname = ''.join(c in util.FILENAME_VALID_CHARS and c or '_' for c in fname)[0:150]
                trans.response.headers["Content-Disposition"] = 'attachment; filename="%s"' % fname
                try:
                    return open(dataset.file_name, 'rb')
                except Exception:
                    raise exceptions.InternalServerError("This dataset contains no content.")
        else:
            raise exceptions.RequestParameterInvalidException("Wrong format parameter specified")
Ejemplo n.º 6
0
                 )
         elif format == 'ajax':
             raise exceptions.NotImplemented(
                 'Not implemented yet. Sorry.')
         else:
             try:
                 response = self.__load_all_filenames(full_import_dir)
             except Exception, exception:
                 log.error('Could not get user import files: %s',
                           str(exception),
                           exc_info=True)
                 raise exceptions.InternalServerError(
                     'Could not get the files from your user directory folder.'
                 )
     else:
         raise exceptions.InternalServerError(
             'Could not get the files from your user directory folder.')
 elif target == 'importdir':
     base_dir = trans.app.config.library_import_dir
     if base_dir is None:
         raise exceptions.ConfigDoesNotAllowException(
             'The configuration of this Galaxy instance does not allow usage of import directory.'
         )
     if format == 'jstree':
         disable = kwd.get('disable', 'folders')
         try:
             importdir_jstree = self.__create_jstree(base_dir, disable)
             response = importdir_jstree.jsonData()
         except Exception, exception:
             log.debug(str(exception))
             raise exceptions.InternalServerError(
                 'Could not create tree representation of the given folder: '
Ejemplo n.º 7
0
    def index(self, trans, **kwd):
        """
        GET /api/remote_files/

        Displays remote files.

        :param  target:      target to load available datasets from, defaults to ftp
            possible values: ftp, userdir, importdir
        :type   target:      str

        :param  format:      requested format of data, defaults to flat
            possible values: flat, jstree, ajax

        :returns:   list of available files
        :rtype:     list
        """
        target = kwd.get('target', None)
        format = kwd.get('format', None)

        if target == 'userdir':
            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_import_dir = os.path.join(user_base_dir, user_login)
            if not os.path.exists(full_import_dir):
                raise exceptions.ObjectNotFound(
                    'You do not have any files in your user directory. Use FTP to upload there.'
                )
            if full_import_dir is not None:
                if format == 'jstree':
                    disable = kwd.get('disable', 'folders')
                    try:
                        userdir_jstree = self.__create_jstree(
                            full_import_dir,
                            disable,
                            whitelist=trans.app.config.
                            user_library_import_symlink_whitelist)
                        response = userdir_jstree.jsonData()
                    except Exception as exception:
                        log.debug(str(exception))
                        raise exceptions.InternalServerError(
                            'Could not create tree representation of the given folder: '
                            + str(full_import_dir))
                    if not response:
                        raise exceptions.ObjectNotFound(
                            'You do not have any files in your user directory. Use FTP to upload there.'
                        )
                elif format == 'ajax':
                    raise exceptions.NotImplemented(
                        'Not implemented yet. Sorry.')
                else:
                    try:
                        response = self.__load_all_filenames(
                            full_import_dir,
                            whitelist=trans.app.config.
                            user_library_import_symlink_whitelist)
                    except Exception as exception:
                        log.error('Could not get user import files: %s',
                                  str(exception),
                                  exc_info=True)
                        raise exceptions.InternalServerError(
                            'Could not get the files from your user directory folder.'
                        )
            else:
                raise exceptions.InternalServerError(
                    'Could not get the files from your user directory folder.')
        elif target == 'importdir':
            base_dir = trans.app.config.library_import_dir
            if base_dir is None:
                raise exceptions.ConfigDoesNotAllowException(
                    'The configuration of this Galaxy instance does not allow usage of import directory.'
                )
            if format == 'jstree':
                disable = kwd.get('disable', 'folders')
                try:
                    importdir_jstree = self.__create_jstree(
                        base_dir,
                        disable,
                        whitelist=trans.app.config.
                        user_library_import_symlink_whitelist)
                    response = importdir_jstree.jsonData()
                except Exception as exception:
                    log.debug(str(exception))
                    raise exceptions.InternalServerError(
                        'Could not create tree representation of the given folder: '
                        + str(base_dir))
            elif format == 'ajax':
                raise exceptions.NotImplemented('Not implemented yet. Sorry.')
            else:
                try:
                    response = self.__load_all_filenames(
                        base_dir,
                        trans.app.config.user_library_import_symlink_whitelist)
                except Exception as exception:
                    log.error('Could not get user import files: %s',
                              str(exception),
                              exc_info=True)
                    raise exceptions.InternalServerError(
                        'Could not get the files from your import directory folder.'
                    )
        else:
            user_ftp_base_dir = trans.app.config.ftp_upload_dir
            if user_ftp_base_dir is None:
                raise exceptions.ConfigDoesNotAllowException(
                    'The configuration of this Galaxy instance does not allow upload from FTP directories.'
                )
            try:
                user_ftp_dir = trans.user_ftp_dir
                if user_ftp_dir is not None:
                    response = self.__load_all_filenames(
                        user_ftp_dir,
                        trans.app.config.user_library_import_symlink_whitelist)
                else:
                    log.warning(
                        'You do not have an FTP directory named as your login at this Galaxy instance.'
                    )
                    return None
            except Exception as exception:
                log.warning('Could not get ftp files: %s',
                            str(exception),
                            exc_info=True)
                return None
        return response
Ejemplo n.º 8
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("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("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("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)
Ejemplo n.º 9
0
    def index(
        self,
        user_ctx: ProvidesUserContext,
        target: str,
        format: Optional[RemoteFilesFormat],
        recursive: Optional[bool],
        disable: Optional[RemoteFilesDisableMode],
    ) -> List[Dict[str, Any]]:
        """Returns a list of remote files available to the user."""

        user_file_source_context = ProvidesUserFileSourcesUserContext(user_ctx)
        default_recursive = False
        default_format = RemoteFilesFormat.uri

        if "://" in target:
            uri = target
        elif target == RemoteFilesTarget.userdir:
            uri = "gxuserimport://"
            default_format = RemoteFilesFormat.flat
            default_recursive = True
        elif target == RemoteFilesTarget.importdir:
            uri = 'gximport://'
            default_format = RemoteFilesFormat.flat
            default_recursive = True
        elif target in [RemoteFilesTarget.ftpdir, 'ftp']:  # legacy, allow both
            uri = 'gxftp://'
            default_format = RemoteFilesFormat.flat
            default_recursive = True
        else:
            raise exceptions.RequestParameterInvalidException(
                f"Invalid target parameter supplied [{target}]")

        if format is None:
            format = default_format

        if recursive is None:
            recursive = default_recursive

        self._file_sources.validate_uri_root(
            uri, user_context=user_file_source_context)

        file_source_path = self._file_sources.get_file_source_path(uri)
        file_source = file_source_path.file_source
        try:
            index = file_source.list(file_source_path.path,
                                     recursive=recursive,
                                     user_context=user_file_source_context)
        except exceptions.MessageException:
            log.warning(f"Problem listing file source path {file_source_path}",
                        exc_info=True)
            raise
        except Exception:
            message = f"Problem listing file source path {file_source_path}"
            log.warning(message, exc_info=True)
            raise exceptions.InternalServerError(message)
        if format == RemoteFilesFormat.flat:
            # rip out directories, ensure sorted by path
            index = [i for i in index if i["class"] == "File"]
            index = sorted(index, key=itemgetter("path"))
        if format == RemoteFilesFormat.jstree:
            if disable is None:
                disable = RemoteFilesDisableMode.folders

            jstree_paths = []
            for ent in index:
                path = ent["path"]
                path_hash = hashlib.sha1(smart_str(path)).hexdigest()
                if ent["class"] == "Directory":
                    path_type = 'folder'
                    disabled = True if disable == RemoteFilesDisableMode.folders else False
                else:
                    path_type = 'file'
                    disabled = True if disable == RemoteFilesDisableMode.files else False

                jstree_paths.append(
                    jstree.Path(
                        path, path_hash, {
                            'type': path_type,
                            'state': {
                                'disabled': disabled
                            },
                            'li_attr': {
                                'full_path': path
                            }
                        }))
            userdir_jstree = jstree.JSTree(jstree_paths)
            index = userdir_jstree.jsonData()

        return index
Ejemplo n.º 10
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))
Ejemplo n.º 11
0
class FoldersController(BaseAPIController, UsesLibraryMixin,
                        UsesLibraryMixinItems):
    @web.expose_api
    def index(self, trans, **kwd):
        """
        GET /api/folders/
        This would normally display a list of folders. However, that would
        be across multiple libraries, so it's not implemented.
        """
        raise exceptions.NotImplemented(
            'Listing all accessible library folders is not implemented.')

    @web.expose_api
    def show(self, trans, id, **kwd):
        """
        show( self, trans, id, **kwd )
        *GET /api/folders/{encoded_folder_id}

        Displays information about a folder.

        :param  id:      the folder's encoded id (required)
        :type   id:      an encoded id string (has to be prefixed by 'F')

        :returns:   dictionary including details of the folder
        :rtype:     dict
        """
        folder_id_without_prefix = self.__cut_the_prefix(id)
        content = self.get_library_folder(trans,
                                          folder_id_without_prefix,
                                          check_ownership=False,
                                          check_accessible=True)
        return_dict = self.encode_all_ids(trans,
                                          content.to_dict(view='element'))
        return_dict['id'] = 'F' + return_dict['id']
        if return_dict['parent_id'] is not None:
            return_dict['parent_id'] = 'F' + return_dict['parent_id']
        return return_dict

    @expose_api
    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))

        library = parent_folder.parent_library
        if library.deleted:
            raise exceptions.ObjectAttributeInvalidException(
                'You cannot create folder within a deleted library. Undelete it first.'
            )

        # TODO: refactor the functionality for use here instead of calling another controller
        params = dict([("name", name), ("description", description)])
        status, output = trans.webapp.controllers[
            'library_common'].create_folder(trans, 'api',
                                            encoded_parent_folder_id, '',
                                            **params)

        if 200 == status and len(output.items()) == 1:
            for k, v in output.items():
                try:
                    folder = trans.sa_session.query(
                        trans.app.model.LibraryFolder).get(v.id)
                except Exception, e:
                    raise exceptions.InternalServerError(
                        'Error loading from the database.' + str(e))
                if folder:
                    update_time = folder.update_time.strftime(
                        "%Y-%m-%d %I:%M %p")
                    return_dict = self.encode_all_ids(
                        trans, folder.to_dict(view='element'))
                    return_dict['update_time'] = update_time
                    return_dict['parent_id'] = 'F' + return_dict['parent_id']
                    return_dict['id'] = 'F' + return_dict['id']
                    return return_dict
Ejemplo n.º 12
0
                    folder = trans.sa_session.query(
                        trans.app.model.LibraryFolder).get(v.id)
                except Exception, e:
                    raise exceptions.InternalServerError(
                        'Error loading from the database.' + str(e))
                if folder:
                    update_time = folder.update_time.strftime(
                        "%Y-%m-%d %I:%M %p")
                    return_dict = self.encode_all_ids(
                        trans, folder.to_dict(view='element'))
                    return_dict['update_time'] = update_time
                    return_dict['parent_id'] = 'F' + return_dict['parent_id']
                    return_dict['id'] = 'F' + return_dict['id']
                    return return_dict
        else:
            raise exceptions.InternalServerError(
                'Error while creating a folder.' + str(e))

    @web.expose_api
    def update(self, trans, id, library_id, payload, **kwd):
        """
        PUT /api/folders/{encoded_folder_id}

        """
        raise exceptions.NotImplemented(
            'Updating folder through this endpoint is not implemented yet.')

    def __cut_the_prefix(self, encoded_id):

        if ((len(encoded_id) % 16 == 1) and encoded_id.startswith('F')):
            return encoded_id[1:]
        else:
Ejemplo n.º 13
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 occurred 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