Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

external survey - skin scoring app #583

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 64 additions & 20 deletions microsetta_private_api/api/_survey.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from microsetta_private_api.repo.transaction import Transaction
from microsetta_private_api.repo.vioscreen_repo import VioscreenRepo
from microsetta_private_api.util import vioscreen, myfoodrepo, vue_adapter, \
polyphenol_ffq
polyphenol_ffq, skin_scoring_app
from microsetta_private_api.util.vioscreen import VioscreenAdminAPI
from microsetta_private_api.config_manager import SERVER_CONFIG

Expand All @@ -34,31 +34,50 @@ def read_survey_templates(account_id, source_id, language_tag, token_info):
with Transaction() as t:
source_repo = SourceRepo(t)
source = source_repo.get_source(account_id, source_id)

if source is None:
return jsonify(code=404, message="No source found"), 404

template_repo = SurveyTemplateRepo(t)

if source.source_type == Source.SOURCE_TYPE_HUMAN:
return jsonify([template_repo.get_survey_template_link_info(x)
for x in [
SurveyTemplateRepo.VIOSCREEN_ID,
SurveyTemplateRepo.POLYPHENOL_FFQ_ID,
SurveyTemplateRepo.SPAIN_FFQ_ID,
SurveyTemplateRepo.BASIC_INFO_ID,
SurveyTemplateRepo.AT_HOME_ID,
SurveyTemplateRepo.LIFESTYLE_ID,
SurveyTemplateRepo.GUT_ID,
SurveyTemplateRepo.GENERAL_HEALTH_ID,
SurveyTemplateRepo.HEALTH_DIAG_ID,
SurveyTemplateRepo.ALLERGIES_ID,
SurveyTemplateRepo.DIET_ID,
SurveyTemplateRepo.DETAILED_DIET_ID,
SurveyTemplateRepo.OTHER_ID
]]), 200
# Checking samples to see if any have
# permission to see Skin Scoring App survey
sample_repo = SampleRepo(t)
samples = sample_repo.get_samples_by_source(account_id, source_id)
if samples:
has_skin_sample = any(
SurveyTemplateRepo.SBI_PROJECT_ID
in s.project_id for s in samples
)
else:
has_skin_sample = False

template_ids = [
SurveyTemplateRepo.VIOSCREEN_ID,
SurveyTemplateRepo.POLYPHENOL_FFQ_ID,
SurveyTemplateRepo.SPAIN_FFQ_ID,
SurveyTemplateRepo.BASIC_INFO_ID,
SurveyTemplateRepo.AT_HOME_ID,
SurveyTemplateRepo.LIFESTYLE_ID,
SurveyTemplateRepo.GUT_ID,
SurveyTemplateRepo.GENERAL_HEALTH_ID,
SurveyTemplateRepo.HEALTH_DIAG_ID,
SurveyTemplateRepo.ALLERGIES_ID,
SurveyTemplateRepo.DIET_ID,
SurveyTemplateRepo.DETAILED_DIET_ID,
SurveyTemplateRepo.OTHER_ID
]
if has_skin_sample:
template_ids.append(SurveyTemplateRepo.SKIN_SCORING_APP_ID)

elif source.source_type == Source.SOURCE_TYPE_ANIMAL:
return jsonify([template_repo.get_survey_template_link_info(x)
for x in [2]]), 200
template_ids = [2]
else:
return jsonify([]), 200
template_ids = []

return jsonify([template_repo.get_survey_template_link_info(x)
for x in template_ids]), 200


def _remote_survey_url_vioscreen(transaction, account_id, source_id,
Expand Down Expand Up @@ -181,6 +200,25 @@ def _remote_survey_url_spain_ffq(transaction, account_id, source_id):
return SERVER_CONFIG['spain_ffq_url']


def _remote_survey_url_skin_scoring_app(transaction,
account_id,
source_id,
language_tag):
st_repo = SurveyTemplateRepo(transaction)

skin_scoring_app_id = \
st_repo.get_skin_scoring_app_id_if_exists(account_id,
source_id)

if skin_scoring_app_id is None:
skin_scoring_app_id = \
st_repo.create_skin_scoring_app_entry(account_id,
source_id,
language_tag)
return skin_scoring_app.gen_url(skin_scoring_app_id,
language_tag)


def read_survey_template(account_id, source_id, survey_template_id,
language_tag, token_info, survey_redirect_url=None,
vioscreen_ext_sample_id=None,
Expand Down Expand Up @@ -220,6 +258,12 @@ def read_survey_template(account_id, source_id, survey_template_id,
url = _remote_survey_url_spain_ffq(t,
account_id,
source_id)
elif survey_template_id == \
SurveyTemplateRepo.SKIN_SCORING_APP_ID:
url = _remote_survey_url_skin_scoring_app(t,
account_id,
source_id,
language_tag)
else:
raise ValueError(f"Cannot generate URL for survey "
f"{survey_template_id}")
Expand Down
36 changes: 36 additions & 0 deletions microsetta_private_api/api/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,42 @@ def test_bobo_takes_polyphenol_ffq(self):
)
check_response(resp, 404)

@skipIf(SERVER_CONFIG['skin_scoring_app_url'] in
('', 'ssa_placeholder'),
"Skin Scoring App secrets not provided")
def test_bobo_takes_skin_scoring_app(self):
bobo = self._bobo_to_claim_a_sample()

# take Skin Scoring App
resp = self.client.get(
'/api/accounts/%s/sources/%s/survey_templates/10005'
'?language_tag=en_US' %
(ACCT_ID, bobo['source_id']),
headers=MOCK_HEADERS
)
check_response(resp)
data = json.loads(resp.data)
exp_start = SERVER_CONFIG['skin_scoring_app_url']
url = data['survey_template_text']['url']
self.assertTrue(url.startswith(exp_start))

# verify we err if we attempt to answer the survey. an "answer" here is
# undefined
resp = self.client.post(
'/api/accounts/%s/sources/%s/surveys'
'?language_tag=en_US' %
(ACCT_ID, bobo['source_id']),
content_type='application/json',
data=json.dumps(
{
"survey_template_id":
SurveyTemplateRepo.SKIN_SCORING_APP_ID,
"survey_text": {'key': 'stuff'}
}),
headers=MOCK_HEADERS
)
check_response(resp, 404)

@skipIf(SERVER_CONFIG['spain_ffq_url'] in ('', 'sffq_placeholder'),
"Spain FFQ secrets not provided")
def test_bobo_takes_spain_ffq(self):
Expand Down
13 changes: 13 additions & 0 deletions microsetta_private_api/db/patches/0143.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CREATE TABLE ag.skin_scoring_app_registry (
skin_scoring_app_id VARCHAR PRIMARY KEY,
account_id UUID NOT NULL,
source_id UUID,
language_tag VARCHAR,
deleted BOOLEAN NOT NULL DEFAULT false,
creation_timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),

CONSTRAINT fk_skin_scoring_app_registry_account FOREIGN KEY (account_id) REFERENCES ag.account(id),
CONSTRAINT fk_skin_scoring_app_registry_source FOREIGN KEY (source_id) REFERENCES ag.source(id)
);

CREATE INDEX skin_scoring_app_registry_source ON ag.skin_scoring_app_registry (account_id, source_id);
16 changes: 16 additions & 0 deletions microsetta_private_api/repo/sample_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ def get_samples_by_source(self, account_id, source_id,
sample.kit_id = self._get_supplied_kit_id_by_sample(
sample.barcode
)
sample.project_id = self._get_project_ids_by_sample(
sample.barcode
)
samples.append(sample)
return samples

Expand Down Expand Up @@ -404,6 +407,19 @@ def _get_supplied_kit_id_by_sample(self, sample_barcode):
row = cur.fetchone()
return row[0]

def _get_project_ids_by_sample(self, sample_barcode):
with self._transaction.cursor() as cur:
cur.execute(
"SELECT project_id "
"FROM barcodes.project_barcode "
"WHERE barcode = %s",
(sample_barcode, )
)
rows = cur.fetchall()

project_ids = [row[0] for row in rows]
return project_ids

def scrub(self, account_id, source_id, sample_id):
"""Wipe out free text information for a sample

Expand Down
95 changes: 94 additions & 1 deletion microsetta_private_api/repo/survey_template_repo.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import random
import string
import psycopg2
from werkzeug.exceptions import NotFound

from microsetta_private_api.config_manager import SERVER_CONFIG
Expand All @@ -23,6 +26,7 @@ class SurveyTemplateRepo(BaseRepo):
MYFOODREPO_ID = 10002
POLYPHENOL_FFQ_ID = 10003
SPAIN_FFQ_ID = 10004
SKIN_SCORING_APP_ID = 10005
BASIC_INFO_ID = 10
AT_HOME_ID = 11
LIFESTYLE_ID = 12
Expand All @@ -36,6 +40,7 @@ class SurveyTemplateRepo(BaseRepo):
SURFERS_ID = 20
COVID19_ID = 21
OTHER_ID = 22
SBI_PROJECT_ID = 58

SURVEY_INFO = {
# For now, let's keep legacy survey info as well.
Expand Down Expand Up @@ -105,6 +110,12 @@ class SurveyTemplateRepo(BaseRepo):
"1.0",
"remote"
),
SKIN_SCORING_APP_ID: SurveyTemplateLinkInfo(
SKIN_SCORING_APP_ID,
"Skin Scoring App",
"1.0",
"remote"
),
BASIC_INFO_ID: SurveyTemplateLinkInfo(
BASIC_INFO_ID,
"Basic Information",
Expand Down Expand Up @@ -755,6 +766,86 @@ def delete_spain_ffq(self, account_id, source_id):
AND source_id=%s""",
(account_id, source_id))

def create_skin_scoring_app_entry(self,
account_id,
source_id,
language_tag,):
"""Return a newly created Skin Scoring App ID

Parameters
----------
account_id : str, UUID
The account UUID
source_id : str, UUID
The source UUID
language_tag: str
The user's language tag

Returns
-------
str
The newly created Skin Scoring App ID
"""
characters = string.ascii_lowercase + string.digits

while True:
skin_scoring_app_id = ''.join(random.choices(characters, k=8))

try:
with self._transaction.cursor() as cur:
cur.execute("""INSERT INTO ag.skin_scoring_app_registry
(skin_scoring_app_id, account_id,
source_id, language_tag)
VALUES (%s, %s, %s, %s)""",
(skin_scoring_app_id, account_id,
source_id, language_tag))

# Put a survey into ag_login_surveys
cur.execute("INSERT INTO ag_login_surveys("
"ag_login_id, "
"survey_id, "
"vioscreen_status, "
"source_id, "
"survey_template_id) "
"VALUES(%s, %s, %s, %s, %s)",
(account_id, skin_scoring_app_id, None,
source_id,
SurveyTemplateRepo.SKIN_SCORING_APP_ID))

return skin_scoring_app_id
except psycopg2.IntegrityError:
self._transaction.rollback()

def get_skin_scoring_app_id_if_exists(self,
account_id,
source_id):
"""Return a Skin Scoring App ID if one exists

Parameters
----------
account_id : str, UUID
The account UUID
source_id : str, UUID
The source UUID

Returns
-------
(str) or (None)
The associated Skin Scoring App ID
It's impossible to find one without the other
"""
with self._transaction.cursor() as cur:
cur.execute("""SELECT skin_scoring_app_id
FROM ag.skin_scoring_app_registry
WHERE account_id=%s AND source_id=%s""",
(account_id, source_id))
res = cur.fetchone()

if res is None:
return None
else:
return res[0]

def get_vioscreen_sample_to_user(self):
"""Obtain a mapping of sample barcode to vioscreen user"""
with self._transaction.cursor() as cur:
Expand Down Expand Up @@ -1127,6 +1218,7 @@ def has_external_surveys(self, account_id, source_id):
getters = (self.get_myfoodrepo_id_if_exists,
self.get_polyphenol_ffq_id_if_exists,
self.get_spain_ffq_id_if_exists,
self.get_skin_scoring_app_id_if_exists,
self.get_vioscreen_all_ids_if_exists)

for get in getters:
Expand Down Expand Up @@ -1306,7 +1398,8 @@ def _generate_empty_survey(self, survey_template_id, return_tuple=False):
if survey_template_id in [self.VIOSCREEN_ID,
self.MYFOODREPO_ID,
self.POLYPHENOL_FFQ_ID,
self.SPAIN_FFQ_ID]:
self.SPAIN_FFQ_ID,
self.SKIN_SCORING_APP_ID]:
raise ValueError("survey_template_id must be for a local "
"survey")
else:
Expand Down
24 changes: 24 additions & 0 deletions microsetta_private_api/repo/tests/test_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,30 @@ def test_get_supplied_kit_id_by_sample(self):
)
self.assertEqual(kit_id, supplied_kit_id)

def test_get_project_ids_by_sample(self):
with Transaction() as t:
# First we'll create a kit so that we have a kit_id/barcode combo
# to test with
admin_repo = AdminRepo(t)
res = admin_repo.create_kits(
1,
1,
"UNITTEST",
[1, 2]
)

# Extract the info from results. We know we created 1 kit with 1
# sample so we don't need to iterate
kit_info = res['created'][0]
sample_barcode = kit_info['sample_barcodes'][0]

# Verify that the function returns the correct project_id
sample_repo = SampleRepo(t)
project_ids = sample_repo._get_project_ids_by_sample(
sample_barcode
)
self.assertEqual([1, 2], project_ids)


if __name__ == '__main__':
unittest.main()
Loading
Loading