Beispiel #1
0
    def test_scrub(self):
        samp1 = 'd8592c74-85f0-2135-e040-8a80115d6401'  # 000001766
        with Transaction() as t:
            acct1, src1 = self._get_source_from_sample(t, samp1)

            sr = SampleRepo(t)

            # get original source associations
            src1_sample = sr.get_samples_by_source(acct1, src1)[0]

            res = sr.scrub(acct1, src1, src1_sample.id)
            self.assertTrue(res)

            obs_sample = sr.get_samples_by_source(acct1, src1)[0]
            self.assertNotEqual(src1_sample.notes, obs_sample.notes)
def _remote_survey_url_polyphenol_ffq(transaction, account_id, source_id,
                                      language_tag):
    st_repo = SurveyTemplateRepo(transaction)

    # right now, ID won't exist
    # future plans to allow surveys to behave more flexibly will use this
    # functionality to allow participants to re-join in-progress surveys
    polyphenol_ffq_id, study = \
        st_repo.get_polyphenol_ffq_id_if_exists(account_id, source_id)

    if polyphenol_ffq_id is None:
        # The Polyphenol FFQ belongs to Danone and they're interested in
        # tracking results that come from their sponsored studies
        # separately from other samples. We pass 'THDMI' as the study for
        # THDMI samples and 'Microsetta' for all other samples. Therefore,
        # we need to determine if the source has any THDMI-associated samples.
        # Without investing significant developer effort to build a category
        # system around projects, a basic text search is the best compromise.
        study = 'Microsetta'
        sample_repo = SampleRepo(transaction)
        samples = sample_repo.get_samples_by_source(account_id, source_id)
        for s in samples:
            for s_p in s.sample_projects:
                if s_p.startswith('THDMI'):
                    study = 'THDMI'
                    break

        polyphenol_ffq_id = st_repo.create_polyphenol_ffq_entry(
            account_id, source_id, language_tag, study)

    return polyphenol_ffq.gen_ffq_url(polyphenol_ffq_id, study, language_tag)
def read_sample_associations(account_id, source_id, token_info):
    _validate_account_access(token_info, account_id)

    with Transaction() as t:
        sample_repo = SampleRepo(t)
        samples = sample_repo.get_samples_by_source(account_id, source_id)

    api_samples = [x.to_api() for x in samples]
    return jsonify(api_samples), 200
Beispiel #4
0
    def test_update_sample_assocation_with_migration(self):
        samp1 = 'd8592c74-85f0-2135-e040-8a80115d6401'  # 000001766
        samp2 = 'ceaa6fd6-0861-4335-aa35-da1857bd5294'  # 000067789

        with Transaction() as t:
            acct1, src1 = self._get_source_from_sample(t, samp1)
            acct2, src2 = self._get_source_from_sample(t, samp2)

            sr = SampleRepo(t)

            # get original source associations
            src1_samples = sr.get_samples_by_source(acct1, src1)
            src2_samples = sr.get_samples_by_source(acct2, src2)

            # verify samples are part of the original source
            self.assertTrue(self._sample_in_source(src1_samples, samp1))
            self.assertTrue(self._sample_in_source(src2_samples, samp2))

            # swap associations
            sr._update_sample_association(samp1, src2, True)
            sr._update_sample_association(samp2, src1, True)

            # get new samples by source
            src1_samples = sr.get_samples_by_source(acct1, src1)
            src2_samples = sr.get_samples_by_source(acct2, src2)

            # verify samples are part of the new source
            self.assertTrue(self._sample_in_source(src1_samples, samp2))
            self.assertTrue(self._sample_in_source(src2_samples, samp1))

            # verify samples are not part of the original source
            self.assertFalse(self._sample_in_source(src1_samples, samp1))
            self.assertFalse(self._sample_in_source(src2_samples, samp2))

            # fix associations
            sr._update_sample_association(samp1, src1, True)
            sr._update_sample_association(samp2, src2, True)

            # ...and verify assocations are fixed
            src1_samples = sr.get_samples_by_source(acct1, src1)
            src2_samples = sr.get_samples_by_source(acct2, src2)
            self.assertTrue(self._sample_in_source(src1_samples, samp1))
            self.assertTrue(self._sample_in_source(src2_samples, samp2))
def delete_account(account_id, token_info):
    validate_admin_access(token_info)

    with Transaction() as t:
        acct_repo = AccountRepo(t)
        src_repo = SourceRepo(t)
        samp_repo = SampleRepo(t)
        sar_repo = SurveyAnswersRepo(t)

        acct = acct_repo.get_account(account_id)
        if acct is None:
            return jsonify(message="Account not found", code=404), 404
        else:
            # the account is already scrubbed so let's stop early
            if acct.account_type == 'deleted':
                return None, 204

        sample_count = 0
        sources = src_repo.get_sources_in_account(account_id)

        for source in sources:
            samples = samp_repo.get_samples_by_source(account_id, source.id)

            has_samples = len(samples) > 0
            sample_count += len(samples)

            for sample in samples:
                # we scrub rather than disassociate in the event that the
                # sample is in our freezers but not with an up-to-date scan
                samp_repo.scrub(account_id, source.id, sample.id)

            surveys = sar_repo.list_answered_surveys(account_id, source.id)
            if has_samples:
                # if we have samples, we need to scrub survey / source
                # free text
                for survey_id in surveys:
                    sar_repo.scrub(account_id, source.id, survey_id)
                src_repo.scrub(account_id, source.id)
            else:
                # if we do not have associated samples, then the source
                # is safe to delete
                for survey_id in surveys:
                    sar_repo.delete_answered_survey(account_id, survey_id)
                src_repo.delete_source(account_id, source.id)

        # an account is safe to delete if there are no associated samples
        if sample_count > 0:
            acct_repo.scrub(account_id)
        else:
            acct_repo.delete_account(account_id)

        t.commit()

    return None, 204
def delete_dummy_accts():
    all_sample_ids = []
    acct_ids = [ACCT_ID_1, ACCT_ID_2]

    with Transaction() as t:
        acct_repo = AccountRepo(t)
        source_repo = SourceRepo(t)
        survey_answers_repo = SurveyAnswersRepo(t)
        sample_repo = SampleRepo(t)

        for curr_acct_id in acct_ids:
            sources = source_repo.get_sources_in_account(curr_acct_id)
            for curr_source in sources:
                source_samples = sample_repo.get_samples_by_source(
                    curr_acct_id, curr_source.id)
                sample_ids = [x.id for x in source_samples]
                all_sample_ids.extend(sample_ids)

                # Dissociate all samples linked to this source from all
                # answered surveys linked to this source, then delete all
                # answered surveys
                delete_dummy_answered_surveys_from_source_with_t(
                    t, curr_acct_id, curr_source.id, sample_ids,
                    survey_answers_repo)

                # Now dissociate all the samples from this source
                for curr_sample_id in sample_ids:
                    sample_repo.dissociate_sample(curr_acct_id, curr_source.id,
                                                  curr_sample_id)

                # Finally, delete the source
                source_repo.delete_source(curr_acct_id, curr_source.id)

            # Delete the account
            acct_repo.delete_account(curr_acct_id)

        # Belt and suspenders: these test emails are used by some tests outside
        # of this module as well, so can't be sure they are paired with the
        # above dummy account ids
        acct_repo.delete_account_by_email(TEST_EMAIL)
        acct_repo.delete_account_by_email(TEST_EMAIL_2)

        # Delete the kit and all samples that were attached to any sources
        # NB: This won't clean up any samples that were created but NOT
        # attached to any sources ...
        if len(all_sample_ids) == 0:
            all_sample_ids = None
        _remove_mock_kit(t, mock_sample_ids=all_sample_ids)

        t.commit()
Beispiel #7
0
    def test_migrate_sample(self):
        samp1 = 'd8592c74-85f0-2135-e040-8a80115d6401'  # 000001766
        samp2 = 'ceaa6fd6-0861-4335-aa35-da1857bd5294'  # 000067789

        with Transaction() as t:
            acct1, src1 = self._get_source_from_sample(t, samp1)
            acct2, src2 = self._get_source_from_sample(t, samp2)
            sr = SampleRepo(t)

            sr.migrate_sample(samp1, src1, src2, True)

            # get new samples by source
            src1_samples = sr.get_samples_by_source(acct1, src1)
            src2_samples = sr.get_samples_by_source(acct2, src2)

            # verify samples are part of the new source
            self.assertFalse(self._sample_in_source(src1_samples, samp1))
            self.assertTrue(self._sample_in_source(src2_samples, samp1))
def query_email_stats(body, token_info):
    validate_admin_access(token_info)

    email_list = body.get("emails", [])
    project = body.get("project")

    results = []
    with Transaction() as t:
        account_repo = AccountRepo(t)
        kit_repo = KitRepo(t)
        source_repo = SourceRepo(t)
        sample_repo = SampleRepo(t)

        for email in email_list:
            result = {'email': email, 'project': project}
            results.append(result)
            # can use internal lookup by email, because we have admin access
            account = account_repo._find_account_by_email(email)  # noqa
            if account is None:
                result['summary'] = "No Account"
                continue
            else:
                result['account_id'] = account.id
                result['creation_time'] = account.creation_time
                result['kit_name'] = account.created_with_kit_id

            if account.created_with_kit_id is not None:
                unused = kit_repo.get_kit_unused_samples(
                             account.created_with_kit_id
                         )
                if unused is None:
                    result['unclaimed-samples-in-kit'] = 0
                else:
                    result['unclaimed-samples-in-kit'] = len(unused.samples)

            sample_statuses = defaultdict(int)
            sources = source_repo.get_sources_in_account(account.id)

            samples_in_project = 0
            for source in sources:
                samples = sample_repo.get_samples_by_source(account.id,
                                                            source.id)
                for sample in samples:
                    if project is not None and \
                       project != "" and \
                       project not in sample.sample_projects:
                        continue
                    samples_in_project += 1
                    sample_status = sample_repo.get_sample_status(
                        sample.barcode,
                        sample._latest_scan_timestamp  # noqa
                    )
                    if sample_status is None:
                        sample_status = "never-scanned"
                    sample_statuses[sample_status] += 1
            result.update(sample_statuses)

            if result.get('unclaimed-samples-in-kit', 0) > 0:
                result['summary'] = 'Possible Unreturned Samples'
            elif samples_in_project == 0:
                result['summary'] = "No Samples In Specified Project"
            elif result.get('sample-is-valid') == samples_in_project:
                result['summary'] = 'All Samples Valid'
            else:
                result['summary'] = 'May Require User Interaction'

    return jsonify(results), 200