Warning

This document is for an in-development version of Galaxy. You can alternatively view this page in the latest release if it exists or view the top of the latest release's documentation.

Source code for galaxy.managers.library_datasets

"""Manager and Serializer for library datasets."""
import logging

from galaxy import util
from galaxy.exceptions import (
    InsufficientPermissionsException,
    InternalServerError,
    ObjectNotFound,
    RequestParameterInvalidException
)
from galaxy.managers import (
    datasets,
    tags
)
from galaxy.util import validation

log = logging.getLogger(__name__)


[docs]class LibraryDatasetsManager(datasets.DatasetAssociationManager): """Interface/service object for interacting with library datasets."""
[docs] def __init__(self, app): self.app = app self.tag_manager = tags.GalaxyTagManager(app.model.context)
[docs] def get(self, trans, decoded_library_dataset_id, check_accessible=True): """ Get the library dataset from the DB. :param decoded_library_dataset_id: decoded library dataset id :type decoded_library_dataset_id: int :param check_accessible: flag whether to check that user can access item :type check_accessible: bool :returns: the requested library dataset :rtype: galaxy.model.LibraryDataset """ try: ld = trans.sa_session.query(trans.app.model.LibraryDataset).filter(trans.app.model.LibraryDataset.table.c.id == decoded_library_dataset_id).one() except Exception as e: raise InternalServerError('Error loading from the database.' + str(e)) ld = self.secure(trans, ld, check_accessible) return ld
[docs] def update(self, trans, ld, payload): """ Update the given library dataset - the latest linked ldda. Updating older lddas (versions) is not allowed. :param ld: library dataset to change :type ld: LibraryDataset :param payload: dictionary structure containing:: :param name: new ld's name, must be longer than 0 :type name: str :param misc_info: new ld's misc info :type misc_info: str :param file_ext: new ld's extension, must exist in the Galaxy registry :type file_ext: str :param genome_build: new ld's genome build :type genome_build: str :type payload: dict :returns: the changed library dataset :rtype: galaxy.model.LibraryDataset """ self.check_modifiable(trans, ld) # we are going to operate on the actual latest ldda ldda = ld.library_dataset_dataset_association payload = self._validate_and_parse_update_payload(payload) self._set_from_dict(trans, ldda, payload) return ld
def _set_from_dict(self, trans, ldda, new_data): changed = False new_name = new_data.get('name', None) if new_name is not None and new_name != ldda.name: ldda.name = new_name changed = True new_misc_info = new_data.get('misc_info', None) if new_misc_info is not None and new_misc_info != ldda.info: ldda.info = new_misc_info changed = True new_message = new_data.get('message', None) if new_message is not None and new_message != ldda.message: ldda.message = new_message changed = True new_file_ext = new_data.get('file_ext', None) if new_file_ext is not None and new_file_ext != ldda.extension: ldda.extension = new_file_ext # TODO trigger set metadata here changed = True new_genome_build = new_data.get('genome_build', None) if new_genome_build is not None and new_genome_build != ldda.dbkey: ldda.dbkey = new_genome_build changed = True if changed: trans.sa_session.add(ldda) trans.sa_session.flush() return changed def _validate_and_parse_update_payload(self, payload): MINIMUM_STRING_LENGTH = 1 validated_payload = {} for key, val in payload.items(): if val is None: continue if key in ('name'): if len(val) < MINIMUM_STRING_LENGTH: raise RequestParameterInvalidException('%s must have at least length of %s' % (key, MINIMUM_STRING_LENGTH)) val = validation.validate_and_sanitize_basestring(key, val) validated_payload[key] = val if key in ('misc_info', 'message'): val = validation.validate_and_sanitize_basestring(key, val) validated_payload[key] = val if key in ('file_ext'): datatype = self.app.datatypes_registry.get_datatype_by_extension(val) if datatype is None: raise RequestParameterInvalidException('This Galaxy does not recognize the datatype of: %s' % (val)) validated_payload[key] = val if key in ('genome_build'): if len(val) < MINIMUM_STRING_LENGTH: raise RequestParameterInvalidException('%s must have at least length of %s' % (key, MINIMUM_STRING_LENGTH)) val = validation.validate_and_sanitize_basestring(key, val) validated_payload[key] = val return validated_payload
[docs] def secure(self, trans, ld, check_accessible=True, check_ownership=False): """ Check if library dataset is accessible to current user or the user is an admin. :param ld: library dataset :type ld: galaxy.model.LibraryDataset :param check_accessible: flag whether to check that user can access library dataset :type check_accessible: bool :returns: the original library dataset :rtype: galaxy.model.LibraryDataset """ if trans.user_is_admin: # all operations are available to an admin return ld if check_accessible: ld = self.check_accessible(trans, ld) return ld
[docs] def check_accessible(self, trans, ld): """ Check whether the current user has permissions to access library dataset. :param ld: library dataset :type ld: galaxy.model.LibraryDataset :returns: the original library dataset :rtype: galaxy.model.LibraryDataset :raises: ObjectNotFound """ if not trans.app.security_agent.can_access_library_item(trans.get_current_user_roles(), ld, trans.user): raise ObjectNotFound('Library dataset with the id provided was not found.') elif ld.deleted: raise ObjectNotFound('Library dataset with the id provided is deleted.') else: return ld
[docs] def check_modifiable(self, trans, ld): """ Check whether the current user has permissions to modify library dataset. :param ld: library dataset :type ld: galaxy.model.LibraryDataset :returns: the original library dataset :rtype: galaxy.model.LibraryDataset :raises: ObjectNotFound """ if ld.deleted: raise ObjectNotFound('Library dataset with the id provided is deleted.') elif trans.user_is_admin: return ld if not trans.app.security_agent.can_modify_library_item(trans.get_current_user_roles(), ld): raise InsufficientPermissionsException('You do not have proper permission to modify this library dataset.') else: return ld
[docs] def serialize(self, trans, ld): """Serialize the library dataset into a dictionary.""" current_user_roles = trans.get_current_user_roles() # Build the full path for breadcrumb purposes. full_path = self._build_path(trans, ld.folder) dataset_item = (trans.security.encode_id(ld.id), ld.name) full_path.insert(0, dataset_item) full_path = full_path[::-1] # Find expired versions of the library dataset expired_ldda_versions = [] for expired_ldda in ld.expired_datasets: expired_ldda_versions.append((trans.security.encode_id(expired_ldda.id), expired_ldda.name)) rval = trans.security.encode_all_ids(ld.to_dict()) if len(expired_ldda_versions) > 0: rval['has_versions'] = True rval['expired_versions'] = expired_ldda_versions ldda = ld.library_dataset_dataset_association if ldda.creating_job_associations: if ldda.creating_job_associations[0].job.stdout: rval['job_stdout'] = ldda.creating_job_associations[0].job.stdout.strip() if ldda.creating_job_associations[0].job.stderr: rval['job_stderr'] = ldda.creating_job_associations[0].job.stderr.strip() if ldda.dataset.uuid: rval['uuid'] = str(ldda.dataset.uuid) rval['deleted'] = ld.deleted rval['folder_id'] = 'F' + rval['folder_id'] rval['full_path'] = full_path rval['file_size'] = util.nice_size(int(ldda.get_size())) rval['date_uploaded'] = ldda.create_time.strftime("%Y-%m-%d %I:%M %p") rval['can_user_modify'] = trans.user_is_admin or trans.app.security_agent.can_modify_library_item(current_user_roles, ld) rval['is_unrestricted'] = trans.app.security_agent.dataset_is_public(ldda.dataset) rval['tags'] = self.tag_manager.get_tags_str(ldda.tags) # Manage dataset permission is always attached to the dataset itself, not the the ld or ldda to maintain consistency rval['can_user_manage'] = trans.user_is_admin or trans.app.security_agent.can_manage_dataset(current_user_roles, ldda.dataset) return rval
def _build_path(self, trans, folder): """ Search the path upwards recursively and load the whole route of names and ids for breadcrumb building purposes. :param folder: current folder for navigating up :param type: Galaxy LibraryFolder :returns: list consisting of full path to the library :type: list """ path_to_root = [] if folder.parent_id is None: # We are almost in root path_to_root.append(('F' + trans.security.encode_id(folder.id), folder.name)) else: # We add the current folder and traverse up one folder. path_to_root.append(('F' + trans.security.encode_id(folder.id), folder.name)) upper_folder = trans.sa_session.query(trans.app.model.LibraryFolder).get(folder.parent_id) path_to_root.extend(self._build_path(trans, upper_folder)) return path_to_root