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)
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
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))
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':
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")
) 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: '
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
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)
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
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))
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
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:
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