Example #1
0
def update_sample(user: User,
                  sample: Sample,
                  new_data: Dict[str, Any],
                  filename: str = None) -> Sample:
    """
    Change the attributes of the sample file with sample_id
    If a key exists in both the file and the db, it will be updated in both.
    :param user:
    :param sample:
    :param new_data:
    :param filename:
    :return:
    """
    if is_write_permitted(user, sample):
        # file attributes and database attributes should be separated
        if 'id' in new_data:
            if sample.id != int(new_data['id']) and Sample.query.filter_by(
                    id=new_data['id']) is not None:
                raise ValueError(
                    f'Sample with id {new_data["id"]} already exists!')
        if 'sample_group_ids' in new_data:
            new_data['sample_group_ids'] = [
                int(sample_group_id)
                for sample_group_id in new_data['sample_group_ids']
            ]
            new_sample_groups = [
                get_sample_group(user, sample_group_id)
                for sample_group_id in new_data['sample_group_ids']
            ]
            remove_sample_groups = [
                sample_group for sample_group in sample.sample_groups
                if sample_group.id not in new_data['sample_group_ids']
            ]
            for sample_group in new_sample_groups:
                if not is_write_permitted(user, sample_group):
                    raise AuthException(
                        f'User {user.email} is not permitted to attach sample {sample.id} to sample group {sample_group.id}'
                    )
            for sample_group in remove_sample_groups:
                if not is_write_permitted(user, sample_group):
                    raise AuthException(
                        f'User {user.email} is not permitted to detach sample {sample.id} from sample group {sample_group.id}'
                    )
            sample.sample_groups = new_sample_groups
        sample.update(new_data)
        if 'file_info' in new_data:
            mdt.update_metadata(sample.filename, new_data['file_info'])
        if filename is not None:
            os.remove(sample.filename)
            shutil.copy(filename, sample.filename)
            os.remove(filename)
        sample.last_editor = user
        sample.filename = f'/data/samples/{sample.id}.h5'
        db.session.commit()
        return sample
    raise AuthException(
        f'User {user.email} is not permitted to modify sample {sample.id}')
Example #2
0
def update_workflow(user: User,
                    workflow: Workflow,
                    new_data: Dict[str, Any],
                    filename: str = None) -> Workflow:
    """
    Update workflow metadata.
    :param user:
    :param workflow:
    :param new_data:
    :parma filename:
    :return:
    """
    if is_write_permitted(user, workflow):
        if 'id' in new_data:
            if workflow.id != int(new_data['id']) and Workflow.query.filter_by(
                    id=new_data['id']) is not None:
                raise ValueError(
                    f'Workflow with id {new_data["id"]} already exists!')
        if 'analysis_ids' in new_data:
            new_analyses = [
                get_analysis(user, analysis_id)
                for analysis_id in new_data['analysis_ids']
            ]
            remove_analyses = [
                analysis for analysis in workflow.analyses
                if analysis.id not in new_data['analysis_ids']
            ]
            for analysis in new_analyses:
                if not is_write_permitted(user, analysis):
                    raise AuthException(
                        f'User {user.email} is not permitted to attach workflow {workflow.id} to analysis {analysis.id}'
                    )
            for analysis in remove_analyses:
                if not is_write_permitted(user, analysis):
                    raise AuthException(
                        f'User {user.email} is not permitted to detach workflow {workflow.id} from analysis {analysis.id}'
                    )
            workflow.analyses = new_analyses
        workflow.update(new_data)
        if 'workflow_definition' in new_data:
            if workflow.file_type == 'json':
                json.dump(new_data['workflow_definition'],
                          open(workflow.filename, 'w+'))
            elif workflow.file_type == 'yaml':
                yaml.dump(new_data['workflow_definition'],
                          open(workflow.filename, 'w+'))
            else:
                open(workflow.filename,
                     'w+').write(new_data['workflow_definition'])
        if filename is not None:
            os.remove(workflow.filename)
            shutil.copy(filename, workflow.filename)
            os.remove(filename)
        db.session.commit()
        return workflow
    raise AuthException(
        f'User {user.email} is not permitted to modify workflow {workflow.id}')
Example #3
0
def update_external_file(user: User,
                         external_file: ExternalFile,
                         new_data: Dict[str, Any],
                         move_file: bool = False,
                         filename: str = None) -> ExternalFile:
    """
    Update the data in the external file record
    :param user:
    :param external_file:
    :param new_data:
    :param move_file:
    :param filename:
    :return:
    """
    if is_write_permitted(user, external_file):
        if 'id' in new_data:
            if external_file.id != int(
                    new_data['id']) and ExternalFile.query.filter_by(
                        id=new_data['id']) is not None:
                raise ValueError(
                    f'External file with id {new_data["id"]} already exists!')
        if 'analysis_ids' in new_data:
            new_analyses = [
                get_analysis(user, analysis_id)
                for analysis_id in new_data['analysis_ids']
            ]
            remove_analyses = [
                analysis for analysis in external_file.analyses
                if analysis.id not in new_data['analysis_ids']
            ]
            for analysis in new_analyses:
                if not is_write_permitted(user, analysis):
                    raise AuthException(
                        f'User {user.email} is not permitted to attach external file {external_file.id} to analysis {analysis.id}'
                    )
            for analysis in remove_analyses:
                if not is_write_permitted(user, analysis):
                    raise AuthException(
                        f'User {user.email} is not permitted to detach external file {external_file.id} from analysis {analysis.id}'
                    )
            external_file.analyses = new_analyses
        if move_file and 'filename' in new_data:
            original_filename = external_file.filename
            shutil.copy(original_filename, new_data['filename'])
            os.remove(original_filename)
        if filename is not None:
            os.remove(external_file.filename)
            shutil.copy(filename, external_file.filename)
            os.remove(filename)
        external_file.update(new_data)
        external_file.last_editor = user
        db.session.commit()
        return external_file
    raise AuthException(
        f'User {user.id} is not permitted to modify external file record {external_file.id}'
    )
Example #4
0
 def __init__(self,
              current_user: User,
              records: List[Union[Sample, Collection]],
              title: str,
              special_vals: List[bool] = None,
              special_val_heading=None):
     super(FileListTableData, self).__init__(current_user)
     self.title = title
     self.special_val_heading = special_val_heading if special_val_heading is not None else ''
     if special_vals is None:
         special_vals = [None for _ in records]
     self.rows = [
         FileListTableRow(record, is_write_permitted(current_user, record),
                          special_val, special_val_heading)
         for record, special_val in zip(records, special_vals)
     ]
     if len(self.rows):
         self.headings = ['ID'] + [
             key for key in self.rows[0].values.keys()
             if key not in {'ID', special_val_heading}
             and all([key in row.values for row in self.rows])
         ]
         if 'ID' not in self.rows[0].values.keys():
             self.headings.remove('ID')
     if len(special_vals) and special_vals[0] is not None:
         self.headings.remove('ID')
         self.headings = [special_val_heading] + self.headings
         if 'ID' in self.rows[0].values.keys():
             self.headings = ['ID'] + self.headings
Example #5
0
def attach_collection(user: User, analysis: Analysis,
                      collection: Collection) -> Dict[str, Any]:
    """
    Add a collection to the list of collections belonging to an analysis
    :param user:
    :param analysis:
    :param collection:
    :return:
    """
    # check read permissions on analysis and collection
    if is_read_permitted(user, collection) and is_write_permitted(
            user, analysis):
        if collection not in analysis.collections:
            analysis.collections.append(collection)
            db.session.commit()
            return {
                'message':
                f'collection {collection.id} attached to analysis {analysis.id}'
            }
        return {
            'message':
            f'Collection {collection.id} already attached to analysis {analysis.id}'
        }
    raise AuthException(
        f'User {user.email} is not permitted to attach collection {collection.id} '
        f'to analysis {analysis.id}')
Example #6
0
def delete_collection(user: User, collection: Collection) -> Dict[str, str]:
    if is_write_permitted(user, collection):
        collection_id = collection.id
        db.session.delete(collection)
        db.session.commit()  # event will handle file deletion
        return {'message': f'collection {collection_id} removed'}
    raise AuthException(f'User {user.email} is not permitted to modify collection {collection.id}')
Example #7
0
def create_new_label_dataset(user: User, collection: Collection, name: str, data_type: str = 'string') -> Dict[str, str]:
    if is_write_permitted(user, collection):
        if re.match('^[^\d\W]\w*$', name):
            collection.create_label_column(name, data_type)
            return {'message': f'Created dataset {name} in collection {collection.id}.'}
        raise ValueError(f'Suggested name {name} is not valid.')
    raise AuthException(f'User {user.email} not permitted to modify collection {collection.id}.')
Example #8
0
 def __init__(self, current_user: User, record: FileRecordMixin):
     super(FileAttributeTableData,
           self).__init__(current_user,
                          is_write_permitted(current_user, record))
     dtypes = record.get_attribute_types()
     self.rows = [
         FileAttributeTableRow(key, value, dtypes[key], self.editable)
         for key, value in record.get_file_attributes().items()
     ]
Example #9
0
 def __init__(self, current_user: User, record: FileRecordMixin):
     super(FileGroupAttributeTableData,
           self).__init__(current_user,
                          is_write_permitted(current_user, record))
     self.rows = [
         FileAttributeTableRow(key, value,
                               type(value).__name__)
         for key, value in record.get_group_attributes().items()
     ]
Example #10
0
def delete_sample_group(user: User, sample_group: SampleGroup) -> Dict[str, str]:
    """
    Delete a sample group.
    :param user:
    :param sample_group:
    :return:
    """
    if is_write_permitted(user, sample_group):
        db.session.delete(sample_group)
        db.session.commit()
        return {'message': f'User group {sample_group.id} deleted'}
    raise AuthException(f'User {user.email} not permitted to modify sample group {sample_group.id}')
Example #11
0
 def __init__(self,
              current_user: User,
              record: Union[OmicsRecordMixin, WorkflowModule, Job],
              record_type: str):
     super(EntryPageData, self).__init__(current_user, is_write_permitted(current_user, record))
     self.id = record.id
     self.name = record.name
     self.update_url = get_update_url(record)
     self.list_url = get_list_url(record)
     self.attribute_table_data = AttributeTableData(current_user, record)
     self.record_type = record_type
     self.admin = current_user.admin
Example #12
0
def update_collection(user: User, collection: Collection, new_data: Dict[str, Any], filename: str = None) -> Collection:
    """
    Update collection attributes
    :param user:
    :param collection:
    :param new_data:
    :return:
    """
    if is_write_permitted(user, collection):
        # file attributes and database attributes should be separated
        if 'id' in new_data:
            if collection.id != int(new_data['id']) and Collection.query.filter_by(id=new_data['id']) is not None:
                raise ValueError(f'Collection with id {new_data["id"]} already exists!')
        # verify write permissions on analyses to attach to or detach from
        if 'analysis_ids' in new_data:
            new_analyses = [get_analysis(user, analysis_id) for analysis_id in new_data['analysis_ids']]
            remove_analyses = [analysis for analysis in collection.analyses
                               if analysis.id not in new_data['analysis_ids']]
            for analysis in new_analyses:
                if not is_write_permitted(user, analysis):
                    raise AuthException(f'User {user.email} is not permitted to attach collection {collection.id} '
                                        f'to analysis {analysis.id}')
            for analysis in remove_analyses:
                if not is_write_permitted(user, analysis):
                    raise AuthException(f'User {user.email} is not permitted to detach collection {collection.id} '
                                        f'from analysis {analysis.id}')
            collection.analyses = new_analyses
        collection.update(new_data)
        if filename is not None:
            os.remove(collection.filename)
            shutil.copy(filename, collection.filename)
            os.remove(filename)
        if 'file_info' in new_data:
            mdt.update_metadata(collection.filename,
                                {key: value for key, value in new_data['file_info'].items()})
        collection.last_editor = user
        db.session.commit()
        return collection
    raise AuthException(f'User {user.email} is not permitted to modify collection {collection.id}')
Example #13
0
def delete_analysis(user: User, analysis: Analysis) -> Dict[str, str]:
    """
    Remove the record associated with this analysis from the database
    :param user:
    :param analysis:
    :return:
    """
    if is_write_permitted(user, analysis):
        db.session.delete(analysis)
        db.session.commit()
        return {'message': f'Analysis {analysis.id} deleted'}
    raise AuthException(
        f'User {user.email} is not permitted to modify analysis {analysis.id}')
Example #14
0
def update_sample_group_attachments(user: User, sample_group: SampleGroup, samples: List[Sample]) -> SampleGroup:
    """
    Make the only samples attached to a group those in sample_ids
    :param user:
    :param sample_group:
    :param samples:
    :return:
    """
    if is_write_permitted(user, sample_group) and all([is_read_permitted(user, sample) for sample in samples]):
        sample_group.samples = samples
        sample_group.last_editor = user
        db.session.commit()
        return sample_group
    raise AuthException(f'User {user.email} not authorized to modify group {sample_group.id}')
Example #15
0
def delete_workflow(user: User, workflow: Workflow) -> Dict[str, str]:
    """
    Delete a workflow from the database and filesystem
    :param user:
    :param workflow:
    :return:
    """
    if is_write_permitted(user, workflow):
        workflow_id = workflow.id
        db.session.delete(workflow)
        db.session.commit()
        return {'message': f'Workflow {workflow_id} deleted.'}
    raise AuthException(
        f'User {user.email} is not permitted to modify analysis {workflow.id}')
Example #16
0
def detach_sample(user: User, sample: Sample, sample_group: SampleGroup) -> SampleGroup:
    """
    Remove a sample from a sample group.
    :param user:
    :param sample:
    :param sample_group:
    :return:
    """
    if is_write_permitted(user, sample_group):
        sample_group.samples.remove(sample)
        sample_group.last_editor = user
        db.session.commit()
        return sample_group
    raise AuthException(f'User {user.email} not permitted to modify group {sample_group.id}')
Example #17
0
def attach_sample(user: User, sample: Sample, sample_group: SampleGroup) -> SampleGroup:
    """
    Make a sample a member of a sample group.
    :param user:
    :param sample:
    :param sample_group:
    :return:
    """
    if is_write_permitted(user, sample_group) and is_read_permitted(user, sample):
        if sample not in sample_group.samples:
            sample_group.samples.append(sample)
        sample_group.last_editor = user
        db.session.commit()
        return sample_group
    raise AuthException(f'User {user.email} is not permitted to attach {sample.id} to group {sample_group.id}')
Example #18
0
def delete_sample(user: User, sample: Sample) -> Dict[str, Any]:
    """
    Delete the sample file with sample_id
    :param user:
    :param sample:
    :return:
    """

    if is_write_permitted(user, sample):
        sample_id = sample.id
        db.session.delete(sample)
        db.session.commit()  # event will handle file deletion
        return {'message': f'Sample {sample_id} removed'}
    raise AuthException(
        f'User {user.email} is not permitted to modify collection {sample.id}')
Example #19
0
def update_collection_array(user: User, collection: Collection, path: str, i: int, j: int, val) -> Collection:
    """
    Update one point of one array in a collection
    :param user:
    :param collection:
    :param path:
    :param i:
    :param j:
    :param val:
    :return:
    """
    if is_write_permitted(user, collection):
        ct.update_array(collection.filename, path, i, j, val)
        return collection
    raise AuthException(f'User {user.email} is not permitted to modify collection {collection.id}.')
 def __init__(self, current_user: User, collection: Collection):
     super(LabelColumnTableData,
           self).__init__(current_user,
                          is_write_permitted(current_user, collection))
     file_info = collection.get_file_info()
     label_datasets = [
         dataset for dataset in file_info['datasets']
         if dataset['rows'] == file_info['max_row_count']
         and dataset['cols'] == 1
     ]
     self.headings = [dataset['path'] for dataset in label_datasets]
     self.columns = {
         path: get_dataset(collection.filename, path, True)
         for path in self.headings
     }
     self.row_count = file_info['max_row_count']
Example #21
0
def update_sample_group(user: User, sample_group: SampleGroup, new_data: Dict[str, Any]) -> SampleGroup:
    """
    Update the data for a sample group.
    :param user:
    :param sample_group:
    :param new_data:
    :return:
    """

    if is_write_permitted(user, sample_group):
        if 'id' in new_data:
            if sample_group.id != new_data['id'] and SampleGroup.query.filter_by(id=new_data['id']) is not None:
                raise ValueError(f'Sample group with id {new_data["id"]} already exists!')
        sample_group.update(new_data)
        sample_group.last_editor = user
        db.session.commit()
        return sample_group
    raise AuthException(f'User {user.email} is not permitted to modify group {sample_group.id}')
Example #22
0
def detach_collection(user: User, analysis: Analysis,
                      collection: Collection) -> Dict[str, Any]:
    """
    Remove a collection from the list of collections belonging to an analysis
    :param user:
    :param analysis:
    :param collection:
    :return:
    """
    if is_write_permitted(user, analysis):
        analysis.collections.remove(collection)
        db.session.commit()
        return {
            'message':
            f'collection {collection.id} detached from analysis {analysis.id}'
        }
    raise AuthException(
        f'User {user.email} is not permitted to modify analysis {analysis.id}')
Example #23
0
def delete_external_file(user: User,
                         external_file: ExternalFile,
                         delete_file: bool = False):
    if is_write_permitted(user, external_file):
        filename = external_file.filename
        record_id = external_file.id
        db.session.delete(external_file)
        db.session.commit()
        if delete_file:
            os.remove(filename)
            return {
                'message':
                f'Deleted external file record {record_id} and file {filename}'
            }
        else:
            return {
                'message':
                f'Deleted external file record {record_id}. File {filename} still exists on disk.'
            }
Example #24
0
def update_analysis(user: User, analysis: Analysis,
                    new_data: Dict[str, Any]) -> Analysis:
    """
    Update the analysis with the data in new_data
    :param user:
    :param analysis:
    :param new_data:
    :return:
    """
    if is_write_permitted(user, analysis):
        if 'id' in new_data:
            if analysis.id != int(new_data['id']) and Analysis.query.filter_by(
                    id=new_data['id']) is not None:
                raise ValueError(
                    f'Analysis with id {new_data["id"]} already exists!')
        analysis.update(new_data)
        analysis.last_editor = user
        db.session.commit()
        return analysis
    raise AuthException(
        f'User {user.email} is not permitted to modify analysis {analysis.id}')
Example #25
0
    def __init__(self, current_user: User, record: Any):
        super(AttributeTableData,
              self).__init__(current_user,
                             is_write_permitted(current_user, record))
        self.values = {
            'ID': AttributeTableRow('id', record.id, False),
            'Name': AttributeTableRow('name', record.name, self.editable)
        }
        if hasattr(record, 'description'):
            self.values['Description'] = AttributeTableRow(
                'description',
                record.description if record.description is not None else '',
                self.editable)
        if isinstance(record, SampleGroup):
            job = get_job(record.upload_job_id)
            self.values['Job'] = AttributeTableRow('job',
                                                   job.name,
                                                   href=get_item_link(job))
        if isinstance(record, User):
            self.values['Email'] = AttributeTableRow(
                'email', record.email, False, href=f'mailto:{record.email}')
            if is_read_permitted(current_user, record.primary_user_group):
                self.values['Primary User Group'] = AttributeTableRow(
                    'primary_user_group', record.primary_user_group.name
                    if record.primary_user_group is not None else None, False,
                    get_item_link(record.primary_user_group)
                    if record.primary_user_group is not None else None)
        if isinstance(record, OmicsRecordMixin):
            if is_read_permitted(current_user, record.owner):
                self.values['Owner'] = AttributeTableRow(
                    'owner',
                    record.owner.name if record.owner is not None else None,
                    False,
                    get_item_link(record.owner)
                    if record.owner is not None else None)
            user_group_options = [
                SelectOption(group.id, group.name, group is record.user_group)
                for group in UserGroup.query.filter(
                    UserGroup.members.contains(current_user)).all()
            ]
            self.values['User Group'] = AttributeTableRow(
                'user_group_id', record.user_group.name
                if record.user_group is not None else None, self.editable,
                None, user_group_options, False)
            permissions_options = [
                SelectOption('all_can_read', 'Anyone can view?',
                             record.all_can_read),
                SelectOption('group_can_read', 'User group members can view?',
                             record.group_can_read),
                SelectOption('all_can_write', 'Anyone can edit or delete?',
                             record.all_can_write),
                SelectOption('group_can_write',
                             'User group members can edit or delete',
                             record.group_can_write)
            ]
            self.values['Permissions'] = AttributeTableRow(
                'permissions',
                None,
                is_write_permitted(current_user, record),
                select_options=permissions_options,
                select_multiple=True,
                select_composite=True)

        if isinstance(record, Collection):
            if record.parent is not None and is_read_permitted(
                    current_user, record.parent):
                self.values['Parent Collection'] = AttributeTableRow(
                    'parent',
                    f'{record.parent.name} (Collection {record.parent.id})',
                    href=get_item_link(record.parent))
            else:
                self.values['Parent Collection'] = AttributeTableRow(
                    'parent', 'None')
            self.values['Kind'] = AttributeTableRow('kind', record.kind)
        if isinstance(record, Job):
            self.values['Type'] = AttributeTableRow('type', record.type)
            self.values['Status'] = AttributeTableRow('status', record.status)
            self.values['Submitted'] = AttributeTableRow(
                'submitted', record.submission)
            self.values['Started'] = AttributeTableRow('start', record.start)
            self.values['Ended'] = AttributeTableRow('end', record.end)
            if is_read_permitted(current_user, record.owner):
                self.values['Submitted By'] = AttributeTableRow(
                    'owner',
                    record.owner.name,
                    href=get_item_link(record.owner))
        if isinstance(record, ExternalFile):
            self.values['Path'] = AttributeTableRow('filename',
                                                    record.filename)
            self.values['File Type'] = AttributeTableRow(
                'file_type', record.file_type)
            file_info = record.get_file_info()
            if file_info is not None:
                size_mb = file_info['st_size'] / (1024 * 1024.0)
                self.values['Size'] = AttributeTableRow(
                    'file_size', f'{size_mb:.3f} MB')
                self.values['File Modified'] = AttributeTableRow(
                    'file_mtime',
                    datetime.fromtimestamp(
                        file_info['st_mtime']).strftime('%-d %b %Y %H:%M'))
        if isinstance(record, Base):
            self.values['Date Created'] = AttributeTableRow(
                'created_on', record.created_on.strftime('%-d %b %Y %H:%M'))
            self.values['Date Modified'] = AttributeTableRow(
                'updated_on', record.updated_on.strftime('%-d %b %Y %H:%M'))