def retrieve_diagnostics_by_kit_id(self, supplied_kit_id): kit_repo = KitRepo(self._transaction) kit = kit_repo.get_kit_all_samples(supplied_kit_id) if kit is None: return None sample_assoc = [] for sample in kit.samples: sample_assoc.append( self.retrieve_diagnostics_by_barcode(sample.barcode, grab_kit=False)) with self._transaction.dict_cursor() as cur: cur.execute( "SELECT " "ag_login_id as account_id " "FROM " "ag_kit " "WHERE " "supplied_kit_id = %s", (supplied_kit_id,)) row = cur.fetchone() pre_microsetta_acct = None if row['account_id'] is not None: acct_repo = AccountRepo(self._transaction) # This kit predated the microsetta migration, let's pull in the # account info associated with it pre_microsetta_acct = acct_repo.get_account(row['account_id']) # obtain information on any accounts created using the kit ID with self._transaction.dict_cursor() as cur: cur.execute( "SELECT id as account_id " "FROM " "account " "WHERE " "created_with_kit_id = %s", (supplied_kit_id, )) rows = cur.fetchall() accounts_created = None if len(rows) > 0: acct_repo = AccountRepo(self._transaction) accounts_created = [acct_repo.get_account(row['account_id']) for row in rows] diagnostic = { 'accounts_created': accounts_created, 'kit_id': kit.id, 'supplied_kit_id': supplied_kit_id, 'kit': kit, 'pre_microsetta_acct': pre_microsetta_acct, 'sample_diagnostic_info': sample_assoc } return diagnostic
def read_kit(kit_name): # NOTE: Nothing in this route requires a particular user to be logged in, # so long as the user has -an- account. with Transaction() as t: kit_repo = KitRepo(t) kit = kit_repo.get_kit_unused_samples(kit_name) if kit is None: return jsonify(code=404, message="No such kit"), 404 return jsonify(kit.to_api()), 200
def register_account(body, token_info): # First register with AuthRocket, then come here to make the account new_acct_id = str(uuid.uuid4()) body["id"] = new_acct_id # Account.from_dict requires a kit_name, even if blank kit_name = body.get("kit_name", "") body["kit_name"] = kit_name code = body.get("code", "") body["code"] = code account_obj = Account.from_dict(body, token_info[JWT_ISS_CLAIM_KEY], token_info[JWT_SUB_CLAIM_KEY]) if kit_name == "" and code == "": return jsonify(code=400, message="Account registration requires " "valid kit ID or activation code"), 400 with Transaction() as t: activation_repo = ActivationRepo(t) if code != "": can_activate, cause = activation_repo.can_activate_with_cause( body["email"], code) if not can_activate: return jsonify(code=404, message=cause), 404 else: activation_repo.use_activation_code(body["email"], code) if kit_name != "": kit_repo = KitRepo(t) kit = kit_repo.get_kit_all_samples(kit_name) if kit is None: return jsonify(code=404, message="Kit name not found"), 404 acct_repo = AccountRepo(t) acct_repo.create_account(account_obj) new_acct = acct_repo.get_account(new_acct_id) t.commit() response = jsonify(new_acct.to_api()) response.status_code = 201 response.headers['Location'] = '/api/accounts/%s' % new_acct_id return response
def register_account(body, token_info): # First register with AuthRocket, then come here to make the account new_acct_id = str(uuid.uuid4()) body["id"] = new_acct_id account_obj = Account.from_dict(body, token_info[JWT_ISS_CLAIM_KEY], token_info[JWT_SUB_CLAIM_KEY]) with Transaction() as t: kit_repo = KitRepo(t) kit = kit_repo.get_kit_all_samples(body['kit_name']) if kit is None: return jsonify(code=404, message="Kit name not found"), 404 acct_repo = AccountRepo(t) acct_repo.create_account(account_obj) new_acct = acct_repo.get_account(new_acct_id) t.commit() response = jsonify(new_acct.to_api()) response.status_code = 201 response.headers['Location'] = '/api/accounts/%s' % new_acct_id return response
def retrieve_diagnostics_by_barcode(self, sample_barcode, grab_kit=True): def _rows_to_dicts_list(rows): return [dict(x) for x in rows] with self._transaction.dict_cursor() as cur: ids = self._get_ids_relevant_to_barcode(sample_barcode) if ids is None: ids = {} # default for not found is None sample_id = ids.get("sample_id") source_id = ids.get("source_id") account_id = ids.get("account_id") # NB: this is the true UUID kit id (the primary key of # ag.ag_kit), NOT the kit's participant-facing string "id" kit_id = ids.get("kit_id") account = None source = None sample = None kit = None # get sample object for this barcode, if any if sample_id is not None: sample_repo = SampleRepo(self._transaction) sample = sample_repo._get_sample_by_id(sample_id) # get account object for this barcode, if any if account_id is not None: account_repo = AccountRepo(self._transaction) account = account_repo.get_account(account_id) # and source object for this barcode, if any if source_id is not None: source_repo = SourceRepo(self._transaction) source = source_repo.get_source(account_id, source_id) # get (partial) projects_info list for this barcode query = f""" SELECT {p.DB_PROJ_NAME_KEY}, {p.IS_MICROSETTA_KEY}, {p.BANK_SAMPLES_KEY}, {p.PLATING_START_DATE_KEY} FROM barcodes.project INNER JOIN barcodes.project_barcode USING (project_id) WHERE barcode=%s;""" cur.execute(query, (sample_barcode, )) # this can't be None; worst-case is an empty list projects_info = _rows_to_dicts_list(cur.fetchall()) # get scans_info list for this barcode # NB: ORDER MATTERS here. Do not change the order unless you # are positive you know what already depends on it. cur.execute( "SELECT barcode_scan_id, barcode, " "scan_timestamp, sample_status, " "technician_notes " "FROM barcodes.barcode_scans " "WHERE barcode=%s " "ORDER BY scan_timestamp asc", (sample_barcode, )) # this can't be None; worst-case is an empty list scans_info = _rows_to_dicts_list(cur.fetchall()) latest_scan = None if len(scans_info) > 0: # NB: the correctness of this depends on the scans (queried # right above) being in ascending order by timestamp latest_scan = scans_info[len(scans_info) - 1] # get details about this barcode itself; CAN be None if the # barcode doesn't exist in db barcode_info = None cur.execute( "SELECT barcode, assigned_on, status, " "sample_postmark_date, biomass_remaining, " "sequencing_status, obsolete, " "create_date_time, kit_id " "FROM barcodes.barcode " "WHERE barcode = %s", (sample_barcode, )) barcode_row = cur.fetchone() if barcode_row is not None: barcode_info = dict(barcode_row) if account is None and source is None and sample is None and \ len(projects_info) == 0 and len(scans_info) == 0 \ and barcode_info is None: return None diagnostic = { "account": account, "source": source, "sample": sample, "latest_scan": latest_scan, "scans_info": scans_info, "barcode_info": barcode_info, "projects_info": projects_info } if grab_kit: # get kit object if kit_id is not None: kit_repo = KitRepo(self._transaction) kit = kit_repo.get_kit_all_samples_by_kit_id(kit_id) diagnostic["kit"] = kit return diagnostic
def retrieve_diagnostics_by_barcode(self, sample_barcode, grab_kit=True): def _rows_to_dicts_list(rows): return [dict(x) for x in rows] with self._transaction.dict_cursor() as cur: ids = self._get_ids_relevant_to_barcode(sample_barcode) if ids is None: sample_id = None source_id = None account_id = None kit_id = None else: sample_id = ids["sample_id"] source_id = ids["source_id"] account_id = ids["account_id"] kit_id = ids["kit_id"] account = None source = None sample = None kit = None # get sample object for this barcode if sample_id is not None: sample_repo = SampleRepo(self._transaction) sample = sample_repo._get_sample_by_id(sample_id) # get account and source objects for this barcode if source_id is not None and account_id is not None: account_repo = AccountRepo(self._transaction) source_repo = SourceRepo(self._transaction) account = account_repo.get_account(account_id) source = source_repo.get_source(account_id, source_id) # get projects_info list for this barcode cur.execute("SELECT project, is_microsetta, " "bank_samples, plating_start_date " "FROM barcodes.project " "INNER JOIN barcodes.project_barcode " "USING (project_id) " "WHERE barcode=%s", (sample_barcode,)) # this can't be None; worst-case is an empty list projects_info = _rows_to_dicts_list(cur.fetchall()) # get scans_info list for this barcode # NB: ORDER MATTERS here. Do not change the order unless you # are positive you know what already depends on it. cur.execute("SELECT barcode_scan_id, barcode, " "scan_timestamp, sample_status, " "technician_notes " "FROM barcodes.barcode_scans " "WHERE barcode=%s " "ORDER BY scan_timestamp asc", (sample_barcode,)) # this can't be None; worst-case is an empty list scans_info = _rows_to_dicts_list(cur.fetchall()) latest_scan = None if len(scans_info) > 0: # NB: the correctness of this depends on the scans (queried # right above) being in ascending order by timestamp latest_scan = scans_info[len(scans_info)-1] # get details about this barcode itself; CAN be None if the # barcode doesn't exist in db barcode_info = None cur.execute("SELECT barcode, assigned_on, status, " "sample_postmark_date, biomass_remaining, " "sequencing_status, obsolete, " "create_date_time, kit_id " "FROM barcodes.barcode " "WHERE barcode = %s", (sample_barcode,)) barcode_row = cur.fetchone() if barcode_row is not None: barcode_info = dict(barcode_row) if account is None and source is None and sample is None and \ len(projects_info) == 0 and len(scans_info) == 0 \ and barcode_info is None: return None diagnostic = { "account": account, "source": source, "sample": sample, "latest_scan": latest_scan, "scans_info": scans_info, "barcode_info": barcode_info, "projects_info": projects_info } if grab_kit: # get kit object if kit_id is not None: kit_repo = KitRepo(self._transaction) kit = kit_repo.get_kit_all_samples_by_kit_id(kit_id) diagnostic["kit"] = kit return diagnostic
def retrieve_diagnostics_by_barcode(self, sample_barcode, grab_kit=True): with self._transaction.dict_cursor() as cur: ids = self._get_ids_relevant_to_barcode(sample_barcode) if ids is None: sample_id = None source_id = None account_id = None kit_id = None else: sample_id = ids["sample_id"] source_id = ids["source_id"] account_id = ids["account_id"] kit_id = ids["kit_id"] account = None source = None sample = None kit = None if sample_id is not None: sample_repo = SampleRepo(self._transaction) sample = sample_repo._get_sample_by_id(sample_id) if source_id is not None and account_id is not None: account_repo = AccountRepo(self._transaction) source_repo = SourceRepo(self._transaction) account = account_repo.get_account(account_id) source = source_repo.get_source(account_id, source_id) if kit_id is not None and grab_kit: kit_repo = KitRepo(self._transaction) kit = kit_repo.get_kit_all_samples_by_kit_id(kit_id) cur.execute("SELECT * from barcodes.barcode " "LEFT OUTER JOIN barcodes.project_barcode " "USING (barcode) " "LEFT OUTER JOIN barcodes.project " "USING (project_id) " "where barcode=%s", (sample_barcode,)) barcode_info = cur.fetchall() # How to unwrap a psycopg2 DictRow. I feel dirty. barcode_info = [{k: v for k, v in x.items()} for x in barcode_info] # Get Inceptioned!! # Collapse info from joined project_barcode and project tables # into array within barcode_info if barcode_info: first = barcode_info[0] first['projects'] = [ { 'project_id': r['project_id'], 'project': r['project'] } for r in barcode_info] del first['project_id'] del first['project'] barcode_info = first else: barcode_info = None if account is None and \ source is None and \ sample is None and \ barcode_info is None: return None diagnostic = { "barcode": sample_barcode, "account": account, "source": source, "sample": sample, "barcode_info": barcode_info } if grab_kit: diagnostic["kit"] = kit return diagnostic
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