From a3c082510f9b310babb5dca5574755c1f21487aa Mon Sep 17 00:00:00 2001 From: ayobi Date: Wed, 18 Sep 2024 23:08:26 -0300 Subject: [PATCH 1/8] init commit --- microsetta_interface/implementation.py | 17 ++++++++++++++++- microsetta_interface/tests/test_integration.py | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/microsetta_interface/implementation.py b/microsetta_interface/implementation.py index 283b6755..5adbdddf 100644 --- a/microsetta_interface/implementation.py +++ b/microsetta_interface/implementation.py @@ -124,6 +124,7 @@ class Source: VIOSCREEN_ID = 10001 MYFOODREPO_ID = 10002 POLYPHENOL_FFQ_ID = 10003 +SKIN_SCORING_APP_FFQ_ID = 10005 SPAIN_FFQ_ID = 10004 SYSTEM_MSG_DICTIONARY = { @@ -398,6 +399,11 @@ class Source: 'est_minutes': '30', 'icon': 'survey_external.svg' }, + SKIN_SCORING_APP_FFQ_ID: { + 'description': 'TBD', + 'est_minutes': 'TBD', + 'icon': 'survey_external.svg' + }, } LOCAL_SURVEY_SEQUENCE = [ BASIC_INFO_ID, @@ -466,7 +472,8 @@ def _get_req_survey_templates_by_source_type(source_type): def _get_opt_survey_templates_by_source_type(source_type): if source_type == Source.SOURCE_TYPE_HUMAN: - return [3, 4, 5, 7, MYFOODREPO_ID, POLYPHENOL_FFQ_ID, SPAIN_FFQ_ID] + return [3, 4, 5, 7, MYFOODREPO_ID, POLYPHENOL_FFQ_ID, + SPAIN_FFQ_ID, SKIN_SCORING_APP_FFQ_ID] elif source_type == Source.SOURCE_TYPE_ANIMAL: return [] elif source_type == Source.SOURCE_TYPE_ENVIRONMENT: @@ -1366,6 +1373,14 @@ def get_fill_source_survey(*, account_id, source_id, "data", reconsent=True ) + # this is remote, so go to an external url, not our jinja2 template + return redirect(survey_output['survey_template_text']['url']) + elif survey_template_id == SKIN_SCORING_APP_FFQ_ID: + if need_reconsent: + return render_consent_page( + account_id, source_id, "data", reconsent=True + ) + # this is remote, so go to an external url, not our jinja2 template return redirect(survey_output['survey_template_text']['url']) else: diff --git a/microsetta_interface/tests/test_integration.py b/microsetta_interface/tests/test_integration.py index ddc4a4e2..f4e8ac90 100644 --- a/microsetta_interface/tests/test_integration.py +++ b/microsetta_interface/tests/test_integration.py @@ -106,6 +106,7 @@ def _fake_jwt(email, verified, uniqify=False): MYFOODREPO_ID = 10002 POLYPHENOL_FFQ_ID = 10003 SPAIN_FFQ_ID = 10004 +SKIN_SCORING_FFQ_ID = 10005 BASIC_INFO_SIMPLE = {"112": "1970"} BASIC_INFO_SIMPLE_ALT = {"112": "1983"} @@ -573,6 +574,11 @@ def _complete_spain_ffq_survey(self, account_id, source_id): f'take_survey?survey_template_id=10004') return self.app.get(url), url + def _complete_skin_scoring_app_ffq_survey(self, account_id, source_id): + url = (f'/accounts/{account_id}/sources/{source_id}/' + f'take_survey?survey_template_id=10005') + return self.app.get(url), url + def test_new_user_to_source_listing(self): resp, url, user_jwt = self._new_to_create() account_id, _, _ = self._ids_from_url(url) From a7d3420f9b63f12a38a5053ed4532753d549f2ca Mon Sep 17 00:00:00 2001 From: ayobi Date: Thu, 19 Sep 2024 23:00:44 -0300 Subject: [PATCH 2/8] removing ffq, adding unique id for ssa card --- microsetta_interface/implementation.py | 13 ++++++++----- microsetta_interface/templates/source.jinja2 | 4 +++- microsetta_interface/tests/test_integration.py | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/microsetta_interface/implementation.py b/microsetta_interface/implementation.py index 2f31ee95..0b92a40c 100644 --- a/microsetta_interface/implementation.py +++ b/microsetta_interface/implementation.py @@ -124,7 +124,7 @@ class Source: VIOSCREEN_ID = 10001 MYFOODREPO_ID = 10002 POLYPHENOL_FFQ_ID = 10003 -SKIN_SCORING_APP_FFQ_ID = 10005 +SKIN_SCORING_APP_ID = 10005 SPAIN_FFQ_ID = 10004 SYSTEM_MSG_DICTIONARY = { @@ -399,7 +399,7 @@ class Source: 'est_minutes': '30', 'icon': 'survey_external.svg' }, - SKIN_SCORING_APP_FFQ_ID: { + SKIN_SCORING_APP_ID: { 'description': 'TBD', 'est_minutes': 'TBD', 'icon': 'survey_external.svg' @@ -473,7 +473,7 @@ def _get_req_survey_templates_by_source_type(source_type): def _get_opt_survey_templates_by_source_type(source_type): if source_type == Source.SOURCE_TYPE_HUMAN: return [3, 4, 5, 7, MYFOODREPO_ID, POLYPHENOL_FFQ_ID, - SPAIN_FFQ_ID, SKIN_SCORING_APP_FFQ_ID] + SPAIN_FFQ_ID, SKIN_SCORING_APP_ID] elif source_type == Source.SOURCE_TYPE_ANIMAL: return [] elif source_type == Source.SOURCE_TYPE_ENVIRONMENT: @@ -1406,7 +1406,7 @@ def get_fill_source_survey(*, # this is remote, so go to an external url, not our jinja2 template return redirect(survey_output['survey_template_text']['url']) - elif survey_template_id == SKIN_SCORING_APP_FFQ_ID: + elif survey_template_id == SKIN_SCORING_APP_ID: if need_reconsent: return render_consent_page( account_id, source_id, "data", reconsent=True @@ -1864,7 +1864,10 @@ def get_source(*, account_id=None, source_id=None): for answer in survey_answers: template_id = answer['survey_template_id'] for template in local_surveys + remote_surveys: - if template['survey_template_id'] == template_id: + if template['survey_template_id'] == 10005: + template['survey_id'] = answer['survey_id'] + template['answered'] = True + else: template['answered'] = True for template in local_surveys: diff --git a/microsetta_interface/templates/source.jinja2 b/microsetta_interface/templates/source.jinja2 index eafd0f76..7e5bdf8b 100644 --- a/microsetta_interface/templates/source.jinja2 +++ b/microsetta_interface/templates/source.jinja2 @@ -128,7 +128,9 @@ {% endif %}
- {% if detail.answered %} + {% if detail.survey_template_id == 10005 %} +
{{ _('COMPLETED') }}
{{ _('Unique ID') }}: {{ detail.survey_id }}
+ {% elif detail.answered %}
{{ _('COMPLETED') }}
{% else %}
{{ _('NEW') }}
diff --git a/microsetta_interface/tests/test_integration.py b/microsetta_interface/tests/test_integration.py index c9c93388..9b63197c 100644 --- a/microsetta_interface/tests/test_integration.py +++ b/microsetta_interface/tests/test_integration.py @@ -106,7 +106,7 @@ def _fake_jwt(email, verified, uniqify=False): MYFOODREPO_ID = 10002 POLYPHENOL_FFQ_ID = 10003 SPAIN_FFQ_ID = 10004 -SKIN_SCORING_FFQ_ID = 10005 +SKIN_SCORING_ID = 10005 BASIC_INFO_SIMPLE = {"112": "1970"} BASIC_INFO_SIMPLE_ALT = {"112": "1983"} @@ -574,7 +574,7 @@ def _complete_spain_ffq_survey(self, account_id, source_id): f'take_survey?survey_template_id=10004') return self.app.get(url), url - def _complete_skin_scoring_app_ffq_survey(self, account_id, source_id): + def _complete_skin_scoring_app_survey(self, account_id, source_id): url = (f'/accounts/{account_id}/sources/{source_id}/' f'take_survey?survey_template_id=10005') return self.app.get(url), url From ed1a35c611795fa22f9af9a9dbe9ac678ef3374c Mon Sep 17 00:00:00 2001 From: ayobi Date: Fri, 20 Sep 2024 21:12:02 -0300 Subject: [PATCH 3/8] show unique id/clickable after completed for project 10005 --- microsetta_interface/templates/source.jinja2 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/microsetta_interface/templates/source.jinja2 b/microsetta_interface/templates/source.jinja2 index 7e5bdf8b..e31b086a 100644 --- a/microsetta_interface/templates/source.jinja2 +++ b/microsetta_interface/templates/source.jinja2 @@ -123,13 +123,13 @@
{% for detail in remote_surveys %} From 331e45c83bacb679f1cd4b622259c82aa78d871b Mon Sep 17 00:00:00 2001 From: ayobi Date: Tue, 24 Sep 2024 14:53:01 -0300 Subject: [PATCH 4/8] change for constants --- microsetta_interface/implementation.py | 5 +++-- microsetta_interface/templates/source.jinja2 | 8 ++++---- microsetta_interface/tests/test_integration.py | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/microsetta_interface/implementation.py b/microsetta_interface/implementation.py index 0b92a40c..c2a1bbea 100644 --- a/microsetta_interface/implementation.py +++ b/microsetta_interface/implementation.py @@ -1864,7 +1864,7 @@ def get_source(*, account_id=None, source_id=None): for answer in survey_answers: template_id = answer['survey_template_id'] for template in local_surveys + remote_surveys: - if template['survey_template_id'] == 10005: + if template['survey_template_id'] == SKIN_SCORING_APP_ID: template['survey_id'] = answer['survey_id'] template['answered'] = True else: @@ -1928,7 +1928,8 @@ def get_source(*, account_id=None, source_id=None): source_name=source_output['source_name'], profile_has_samples=profile_has_samples, need_reconsent=need_reconsent, - show_update_age=show_update_age + show_update_age=show_update_age, + SKIN_SCORING_APP_ID=SKIN_SCORING_APP_ID ) diff --git a/microsetta_interface/templates/source.jinja2 b/microsetta_interface/templates/source.jinja2 index e31b086a..691dad86 100644 --- a/microsetta_interface/templates/source.jinja2 +++ b/microsetta_interface/templates/source.jinja2 @@ -123,12 +123,12 @@
{% for detail in remote_surveys %} diff --git a/microsetta_interface/tests/test_integration.py b/microsetta_interface/tests/test_integration.py index 9b63197c..942b96aa 100644 --- a/microsetta_interface/tests/test_integration.py +++ b/microsetta_interface/tests/test_integration.py @@ -106,7 +106,7 @@ def _fake_jwt(email, verified, uniqify=False): MYFOODREPO_ID = 10002 POLYPHENOL_FFQ_ID = 10003 SPAIN_FFQ_ID = 10004 -SKIN_SCORING_ID = 10005 +SKIN_SCORING_APP_ID = 10005 BASIC_INFO_SIMPLE = {"112": "1970"} BASIC_INFO_SIMPLE_ALT = {"112": "1983"} @@ -576,7 +576,7 @@ def _complete_spain_ffq_survey(self, account_id, source_id): def _complete_skin_scoring_app_survey(self, account_id, source_id): url = (f'/accounts/{account_id}/sources/{source_id}/' - f'take_survey?survey_template_id=10005') + f'take_survey?survey_template_id={SKIN_SCORING_APP_ID}') return self.app.get(url), url def test_new_user_to_source_listing(self): From 07c57c305093c4b215487ddeb390106e82095712 Mon Sep 17 00:00:00 2001 From: Cassidy Symons Date: Fri, 31 Jan 2025 11:16:21 -0800 Subject: [PATCH 5/8] Partial refactor --- microsetta_interface/implementation.py | 55 ++++++++++++++-- microsetta_interface/routes.yaml | 16 +++++ microsetta_interface/templates/source.jinja2 | 68 ++++++++++++++++++-- 3 files changed, 128 insertions(+), 11 deletions(-) diff --git a/microsetta_interface/implementation.py b/microsetta_interface/implementation.py index 3f4fe073..cabd4be7 100644 --- a/microsetta_interface/implementation.py +++ b/microsetta_interface/implementation.py @@ -400,8 +400,18 @@ class Source: 'icon': 'survey_external.svg' }, SKIN_SCORING_APP_ID: { - 'description': 'TBD', - 'est_minutes': 'TBD', + 'description': 'This will direct you to the ModiFace skin-scoring web ' + 'app. This app allows you to upload a selfie photo, ' + 'which will be used to generate anonymized data about ' + 'your skin for researchers and provide you with what ' + 'the algorithm assesses to be your top two skin ' + 'concerns. You will be provided a username and password' + ' on the next screen to access the app, which will link' + ' your ModiFace results to your skin sample. This app ' + 'is hosted by a third-party provider; we are ' + 'unable to provide any assistance if you encounter ' + 'errors or issues while using the app.', + 'est_minutes': '5', 'icon': 'survey_external.svg' }, } @@ -1557,6 +1567,26 @@ def get_myfoodrepo_no_slots(*, account_id=None, source_id=None): source_id=source_id) +@prerequisite([SOURCE_PREREQS_MET, BIOSPECIMEN_PREREQS_MET]) +def post_ajax_skin_scoring_app_credentials(*, account_id, source_id): + need_reconsent = check_current_consent(account_id, source_id, "data") + + if need_reconsent: + return render_consent_page( + account_id, source_id, "data", reconsent=True + ) + + has_error, credentials, _ = ApiRequest.post( + "/accounts/%s/sources/%s/surveys/skin_scoring_app_credentials"\ + % (account_id, source_id) + ) + if has_error == 404: + # No available slots, handle this gracefully + return flask.jsonify({"app_username": None, "app_password": None}) + else: + return flask.jsonify(credentials) + + @prerequisite([SOURCE_PREREQS_MET, BIOSPECIMEN_PREREQS_MET]) def get_fill_vioscreen_remote_sample_survey(*, account_id=None, @@ -1897,11 +1927,24 @@ def get_source(*, account_id=None, source_id=None): template['est_minutes'] = SURVEY_INFO[template_id]['est_minutes'] template['icon'] = SURVEY_INFO[template_id]['icon'] - # TODO: MyFoodRepo logic needs to be refactored when we reactivate it - """ # any survey specific stuff like opening a tab # or slot checking - for idx, template in enumerate(remote_surveys[:]): + # NB: change "_" back to "idx" when MyFoodRepo is reactivated or if + # another external survey requires similar functionality + for _, template in enumerate(remote_surveys[:]): + if template['survey_template_id'] == SKIN_SCORING_APP_ID: + has_error, credentials, _ = ApiRequest.get( + '/accounts/%s/sources/%s/surveys/skin_scoring_app_credentials' + % (account_id, source_id) + ) + + if has_error: + return has_error + + template['credentials'] = credentials + + # TODO: MyFoodRepo logic needs to be refactored when we reactivate it + """ if template['survey_template_id'] == MYFOODREPO_ID: has_error, slots, _ = ApiRequest.get('/slots/myfoodrepo') if has_error: @@ -1914,7 +1957,7 @@ def get_source(*, account_id=None, source_id=None): per_source_not_taken.pop(idx) else: template['new_tab'] = False - """ + """ local_surveys = [translate_survey_template(s) for s in local_surveys] remote_surveys = [translate_survey_template(s) for s in remote_surveys] diff --git a/microsetta_interface/routes.yaml b/microsetta_interface/routes.yaml index 75fd7842..8cad9bf9 100644 --- a/microsetta_interface/routes.yaml +++ b/microsetta_interface/routes.yaml @@ -835,6 +835,22 @@ paths: '302': description: Redirecting to necessary action + '/accounts/{account_id}/sources/{source_id}/create_skin_scoring_app_credentials': + post: + operationId: microsetta_interface.implementation.post_ajax_skin_scoring_app_credentials + tags: + - Survey + parameters: + - $ref: '#/components/parameters/account_id' + - $ref: '#/components/parameters/source_id' + responses: + '200': + description: Credentials for skin scoring app + content: + application/json: + schema: + type: object + '/accounts/{account_id}/sources/{source_id}/vioscreen_ffq': get: operationId: microsetta_interface.implementation.get_fill_vioscreen_remote_sample_survey diff --git a/microsetta_interface/templates/source.jinja2 b/microsetta_interface/templates/source.jinja2 index 691dad86..fbb69687 100644 --- a/microsetta_interface/templates/source.jinja2 +++ b/microsetta_interface/templates/source.jinja2 @@ -45,6 +45,40 @@ } {% endif %} + let ssa_username = ''; + let ssa_password = '' + + function handleSkinAppModal(survey_link, survey_title, survey_description, app_username, app_password) { + $("#skin-app-modal-title").empty(); + $("#skin-app-modal-title").text(survey_title); + $("#skin-app-survey-description").empty(); + $("#skin-app-survey-description").text(survey_description); + + if(app_username != '' && app_username != 'None') { + console.log(app_username); + ssa_username = app_username; + ssa_password = app_password; + document.getElementById("app-credentials-div").style.display = ''; + + // Once we display the credentials, the button action is to open the actual survey + $("#skin-app-take-survey").click(async function(e) { + window.open(survey_link, '_blank').focus(); + $("#skin_app_modal").modal('hide'); + + // We need to wait a couple of seconds for the external survey to register in the database, then reload the page. This is not ideal. + await new Promise(r => setTimeout(r, 5000)); + window.location.reload(); + }); + } else { + document.getElementById("app-credentials-div").style.display = 'none'; + $("#skin-app-take-survey").click(async function(e) { + alert("Get credentials here!"); + }); + } + $("#skin_app_modal").modal('show'); + return false; + } + function hideModal() { $("#source_modal").modal('hide'); return false; @@ -123,14 +157,16 @@
{% for detail in remote_surveys %}
- {% if detail.survey_template_id == SKIN_SCORING_APP_ID or not detail.answered %} - + {% if detail.survey_template_id == SKIN_SCORING_APP_ID %} + + {% else %} + {% if not detail.answered %} + + {% endif %} {% endif %}
- {% if detail.survey_template_id == SKIN_SCORING_APP_ID and detail.answered %} -
{{ _('COMPLETED') }}
{{ _('Unique ID') }}: {{ detail.survey_id }}
- {% elif detail.answered %} + {% if detail.answered %}
{{ _('COMPLETED') }}
{% else %}
{{ _('NEW') }}
@@ -181,4 +217,26 @@
+ + {% endblock %} From 7ea99249349f40275990977b6234bce71547d1f5 Mon Sep 17 00:00:00 2001 From: Cassidy Symons Date: Tue, 4 Feb 2025 14:39:23 -0800 Subject: [PATCH 6/8] Finish refactor --- microsetta_interface/implementation.py | 3 +- microsetta_interface/templates/source.jinja2 | 68 +++++++++++++++----- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/microsetta_interface/implementation.py b/microsetta_interface/implementation.py index cabd4be7..4f39505f 100644 --- a/microsetta_interface/implementation.py +++ b/microsetta_interface/implementation.py @@ -1581,8 +1581,7 @@ def post_ajax_skin_scoring_app_credentials(*, account_id, source_id): % (account_id, source_id) ) if has_error == 404: - # No available slots, handle this gracefully - return flask.jsonify({"app_username": None, "app_password": None}) + return flask.jsonify({"app_username": "", "app_password": ""}) else: return flask.jsonify(credentials) diff --git a/microsetta_interface/templates/source.jinja2 b/microsetta_interface/templates/source.jinja2 index fbb69687..b5c0e4df 100644 --- a/microsetta_interface/templates/source.jinja2 +++ b/microsetta_interface/templates/source.jinja2 @@ -45,8 +45,8 @@ } {% endif %} - let ssa_username = ''; - let ssa_password = '' + let skin_app_username = ''; + let skin_app_password = ''; function handleSkinAppModal(survey_link, survey_title, survey_description, app_username, app_password) { $("#skin-app-modal-title").empty(); @@ -54,25 +54,50 @@ $("#skin-app-survey-description").empty(); $("#skin-app-survey-description").text(survey_description); + // We allow the function to update the global variables, which will happen when the user receives credentials and re-renders the modal. + // However, there's no situation where we'd retract the credentials, so we don't need to do anything with blank values. if(app_username != '' && app_username != 'None') { - console.log(app_username); - ssa_username = app_username; - ssa_password = app_password; + skin_app_username = app_username + skin_app_password = app_password + } + + if(skin_app_username != '') { + $("#skin-app-take-survey").html('{{ _('Take This Survey Now') }}'); + document.getElementById("app-credentials-div").style.display = ''; + document.getElementById("app-credentials-username").innerHTML = skin_app_username; + document.getElementById("app-credentials-password").innerHTML = skin_app_password; // Once we display the credentials, the button action is to open the actual survey - $("#skin-app-take-survey").click(async function(e) { + $("#skin-app-take-survey").click(function(e) { window.open(survey_link, '_blank').focus(); - $("#skin_app_modal").modal('hide'); - - // We need to wait a couple of seconds for the external survey to register in the database, then reload the page. This is not ideal. - await new Promise(r => setTimeout(r, 5000)); - window.location.reload(); }); } else { + $("#skin-app-take-survey").html('{{ _('Get Username and Password') }}'); + document.getElementById("app-credentials-div").style.display = 'none'; $("#skin-app-take-survey").click(async function(e) { - alert("Get credentials here!"); + let url = '/accounts/{{ account_id }}/sources/{{ source_id }}/create_skin_scoring_app_credentials'; + $.ajax({ + url: url, + type: "POST", + success: function(data) { + if(!Object.hasOwn(data, 'app_username')) { + // The response doesn't have credentials, something went very wrong. Handle it gracefully. + document.getElementById("app-error").style.display = ''; + } else { + let s_user = data['app_username']; + let s_pass = data['app_password']; + if (s_user.length < 1) { + // We weren't able to allocate them credentials. + document.getElementById("app-error").style.display = ''; + } else { + // We got credentials, refresh this modal + handleSkinAppModal(survey_link, survey_title, survey_description, s_user, s_pass); + } + } + } + }); }); } $("#skin_app_modal").modal('show'); @@ -83,6 +108,11 @@ $("#source_modal").modal('hide'); return false; } + + function hideSkinModal() { + $("#skin_app_modal").modal('hide'); + return false; + } {% endblock %} @@ -217,6 +247,7 @@
+