Skip to content

Commit

Permalink
Adds ability to get project info without stats (for speed)
Browse files Browse the repository at this point in the history
  • Loading branch information
AmandaBirmingham committed Oct 15, 2020
1 parent b4847e3 commit 71caf2b
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 41 deletions.
4 changes: 2 additions & 2 deletions microsetta_private_api/admin/admin_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ def validate_admin_access(token_info):
raise Unauthorized()


def get_projects(token_info, is_active=None):
def get_projects(token_info, include_stats, is_active=None):
validate_admin_access(token_info)

with Transaction() as t:
admin_repo = AdminRepo(t)
projects_list = admin_repo.get_projects(is_active)
projects_list = admin_repo.get_projects(include_stats, is_active)
result = [x.to_api() for x in projects_list]
return jsonify(result), 200

Expand Down
66 changes: 57 additions & 9 deletions microsetta_private_api/admin/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ def test_get_survey(self):
survey)
self.assertTrue(found)

def _set_up_and_query_projects(self, t, is_active_val):
def _set_up_and_query_projects(self, t, include_stats, is_active_val):
updated_dict = self._FULL_PROJECT_DICT.copy()
updated_dict[p.PROJ_NAME_KEY] = 'test_proj'
input = p.Project.from_dict(updated_dict)
Expand Down Expand Up @@ -570,10 +570,10 @@ def _set_up_and_query_projects(self, t, is_active_val):
with t.cursor() as cur:
cur.execute(set_up_sql)

output = admin_repo.get_projects(is_active_val)
output = admin_repo.get_projects(include_stats, is_active_val)

updated_dict["project_id"] = 8
updated_dict[p.COMPUTED_STATS_KEY] = \
computed_stats = \
{p.NUM_FULLY_RETURNED_KITS_KEY: 1,
p.NUM_KITS_KEY: 5,
p.NUM_KITS_W_PROBLEMS_KEY: 1,
Expand All @@ -587,12 +587,60 @@ def _set_up_and_query_projects(self, t, is_active_val):
p.NUM_SAMPLES_RECEIVED_KEY: 5,
p.NUM_UNIQUE_SOURCES_KEY: 4}

updated_dict[p.COMPUTED_STATS_KEY] = \
computed_stats if include_stats else {}

return updated_dict, output

def test_get_projects_all(self):
def test_get_projects_all_w_stats(self):
with Transaction() as t:
updated_dict, output = self._set_up_and_query_projects(
t, include_stats=True, is_active_val=None)

# Test we have the correct number of total projects
self.assertEqual(len(output), 56)

# For one fully-characterized test project, ensure all the
# output values are what we expect (project 8)
self.assertEqual(updated_dict, output[7].to_api())

def test_get_projects_active_w_stats(self):
with Transaction() as t:
updated_dict, output = self._set_up_and_query_projects(
t, include_stats=True, is_active_val=True)

# Test we have the correct number of active projects
self.assertEqual(len(output), 55)

# For one fully-characterized test project, ensure all the
# output values are what we expect. Project 8 is now 7th in
# list (note zero-based) bc project 2 is inactive, so not returned
self.assertEqual(updated_dict, output[6].to_api())

def test_get_projects_inactive_w_stats(self):
with Transaction() as t:
with t.cursor() as cur:
cur.execute("UPDATE barcodes.project"
" SET is_active = FALSE"
" WHERE project_id = 8;")

updated_dict, output = self._set_up_and_query_projects(
t, include_stats=True, is_active_val=False)

updated_dict["is_active"] = False

# Test we have the correct number of inactive projects
self.assertEqual(len(output), 2)

# For one fully-characterized test project, ensure all the
# output values are what we expect. Project 8 is now inactive,
# and is 2nd in (zero-based) list, after project 2
self.assertEqual(updated_dict, output[1].to_api())

def test_get_projects_all_wo_stats(self):
with Transaction() as t:
updated_dict, output = self._set_up_and_query_projects(
t, is_active_val=None)
t, include_stats=False, is_active_val=None)

# Test we have the correct number of total projects
self.assertEqual(len(output), 56)
Expand All @@ -601,10 +649,10 @@ def test_get_projects_all(self):
# output values are what we expect (project 8)
self.assertEqual(updated_dict, output[7].to_api())

def test_get_projects_active(self):
def test_get_projects_active_wo_stats(self):
with Transaction() as t:
updated_dict, output = self._set_up_and_query_projects(
t, is_active_val=True)
t, include_stats=False, is_active_val=True)

# Test we have the correct number of active projects
self.assertEqual(len(output), 55)
Expand All @@ -614,15 +662,15 @@ def test_get_projects_active(self):
# list (note zero-based) bc project 2 is inactive, so not returned
self.assertEqual(updated_dict, output[6].to_api())

def test_get_projects_inactive(self):
def test_get_projects_inactive_wo_stats(self):
with Transaction() as t:
with t.cursor() as cur:
cur.execute("UPDATE barcodes.project"
" SET is_active = FALSE"
" WHERE project_id = 8;")

updated_dict, output = self._set_up_and_query_projects(
t, is_active_val=False)
t, include_stats=False, is_active_val=False)

updated_dict["is_active"] = False

Expand Down
174 changes: 168 additions & 6 deletions microsetta_private_api/admin/tests/test_admin_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,10 @@ def test_update_project(self):
expected_result["project_id"] = proj_id
self.assertEqual(expected_result, stored_result)

def test_get_projects_all(self):
def test_get_projects_all_w_stats(self):
# execute projects get
response = self.client.get(
"/api/admin/projects",
"/api/admin/projects?include_stats=true",
headers=MOCK_HEADERS
)

Expand Down Expand Up @@ -348,10 +348,10 @@ def test_get_projects_all(self):
self.assertEqual(56, len(response_obj))
self.assertEqual(expected_record, response_obj[7])

def test_get_projects_active(self):
def test_get_projects_active_w_stats(self):
# execute projects get
response = self.client.get(
"/api/admin/projects?is_active=true",
"/api/admin/projects?include_stats=true&is_active=true",
headers=MOCK_HEADERS
)

Expand Down Expand Up @@ -414,10 +414,10 @@ def test_get_projects_active(self):
self.assertEqual(55, len(response_obj))
self.assertEqual(expected_record, response_obj[6])

def test_get_projects_inactive(self):
def test_get_projects_inactive_w_stats(self):
# execute projects get
response = self.client.get(
"/api/admin/projects?is_active=false",
"/api/admin/projects?include_stats=true&is_active=false",
headers=MOCK_HEADERS
)

Expand Down Expand Up @@ -480,6 +480,168 @@ def test_get_projects_inactive(self):
self.assertEqual(1, len(response_obj))
self.assertEqual(expected_record, response_obj[0])

def test_get_projects_all_wo_stats(self):
# execute projects get
response = self.client.get(
"/api/admin/projects?include_stats=false",
headers=MOCK_HEADERS
)

# check response code
self.assertEqual(200, response.status_code)

# load the response body
response_obj = json.loads(response.data)

expected_record = {'additional_contact_name': None,
'alias': None,
'bank_samples': False,
'branding_associated_instructions': None,
'branding_status': None,
'collection': None,
'computed_stats': {},
'contact_email': None,
'contact_name': None,
'coordination': None,
'deadlines': None,
'disposition_comments': None,
'do_16s': None,
'do_mass_spec': None,
'do_metatranscriptomics': None,
'do_other': None,
'do_rt_qpcr': None,
'do_serology': None,
'do_shallow_shotgun': None,
'do_shotgun': None,
'is_blood': None,
'is_fecal': None,
'is_microsetta': False,
'is_other': None,
'is_saliva': None,
'is_skin': None,
'mass_spec_comments': None,
'mass_spec_contact_email': None,
'mass_spec_contact_name': None,
'num_subjects': None,
'num_timepoints': None,
'plating_start_date': None,
'project_id': 8,
'project_name': 'Project - %u[zGmÅq=g',
'sponsor': None,
'start_date': None,
'subproject_name': None,
'is_active': True}
self.assertEqual(56, len(response_obj))
self.assertEqual(expected_record, response_obj[7])

def test_get_projects_active_wo_stats(self):
# execute projects get
response = self.client.get(
"/api/admin/projects?include_stats=false&is_active=true",
headers=MOCK_HEADERS
)

# check response code
self.assertEqual(200, response.status_code)

# load the response body
response_obj = json.loads(response.data)

expected_record = {'additional_contact_name': None,
'alias': None,
'bank_samples': False,
'branding_associated_instructions': None,
'branding_status': None,
'collection': None,
'computed_stats': {},
'contact_email': None,
'contact_name': None,
'coordination': None,
'deadlines': None,
'disposition_comments': None,
'do_16s': None,
'do_mass_spec': None,
'do_metatranscriptomics': None,
'do_other': None,
'do_rt_qpcr': None,
'do_serology': None,
'do_shallow_shotgun': None,
'do_shotgun': None,
'is_blood': None,
'is_fecal': None,
'is_microsetta': False,
'is_other': None,
'is_saliva': None,
'is_skin': None,
'mass_spec_comments': None,
'mass_spec_contact_email': None,
'mass_spec_contact_name': None,
'num_subjects': None,
'num_timepoints': None,
'plating_start_date': None,
'project_id': 8,
'project_name': 'Project - %u[zGmÅq=g',
'sponsor': None,
'start_date': None,
'subproject_name': None,
'is_active': True}
self.assertEqual(55, len(response_obj))
self.assertEqual(expected_record, response_obj[6])

def test_get_projects_inactive_wo_stats(self):
# execute projects get
response = self.client.get(
"/api/admin/projects?include_stats=false&is_active=false",
headers=MOCK_HEADERS
)

# check response code
self.assertEqual(200, response.status_code)

# load the response body
response_obj = json.loads(response.data)

expected_record = {'additional_contact_name': None,
'alias': None,
'bank_samples': False,
'branding_associated_instructions': None,
'branding_status': None,
'collection': None,
'computed_stats': {},
'contact_email': None,
'contact_name': None,
'coordination': None,
'deadlines': None,
'disposition_comments': None,
'do_16s': None,
'do_mass_spec': None,
'do_metatranscriptomics': None,
'do_other': None,
'do_rt_qpcr': None,
'do_serology': None,
'do_shallow_shotgun': None,
'do_shotgun': None,
'is_active': False,
'is_blood': None,
'is_fecal': None,
'is_microsetta': False,
'is_other': None,
'is_saliva': None,
'is_skin': None,
'mass_spec_comments': None,
'mass_spec_contact_email': None,
'mass_spec_contact_name': None,
'num_subjects': None,
'num_timepoints': None,
'plating_start_date': None,
'project_id': 2,
'project_name': 'Project - /J/xL_|Eãt',
'sponsor': None,
'start_date': None,
'subproject_name': None}
self.assertEqual(1, len(response_obj))
self.assertEqual(expected_record, response_obj[0])

def test_scan_barcode_success(self):
"""Store info on new scan for valid barcode"""

Expand Down
22 changes: 15 additions & 7 deletions microsetta_private_api/api/microsetta_private_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,7 @@ paths:
summary: Retrieve a list of existing projects
description: Retrieve a list of existing projects
parameters:
- $ref: '#/components/parameters/include_stats'
- $ref: '#/components/parameters/is_active'
responses:
'200':
Expand Down Expand Up @@ -1342,13 +1343,6 @@ components:
description: Project ID
schema:
$ref: '#/components/schemas/project_id'
is_active:
name: is_active
in: query
description: active status of projects by which to limit returned project list; may be true or false. Optional.
schema:
$ref: '#/components/schemas/is_active'


# query parameters
kit_name:
Expand Down Expand Up @@ -1386,6 +1380,19 @@ components:
description: Type of sample
schema:
$ref: '#/components/schemas/source_type'
is_active:
name: is_active
in: query
description: active status of projects by which to limit returned project list; may be true or false. Optional.
schema:
$ref: '#/components/schemas/is_active'
include_stats:
name: include_stats
in: query
description: true if computed statistics about projects should be included in projects list (takes longer)
schema:
type: boolean

responses:
401Unauthorized: # Can be referenced as '#/components/responses/401Unauthorized'
description: Invalid or missing token.
Expand All @@ -1411,6 +1418,7 @@ components:
application/json:
schema:
$ref: '#/components/schemas/Error'

schemas:
# account section
account_id:
Expand Down

0 comments on commit 71caf2b

Please sign in to comment.