From 5cd24cf6faab4dbd382c632477d6a8208cebc283 Mon Sep 17 00:00:00 2001 From: ayobi Date: Mon, 13 May 2024 19:53:59 -0400 Subject: [PATCH 1/9] init fixed vocab for sample issues --- microsetta_admin/server.py | 14 +++++++---- microsetta_admin/templates/scan.html | 37 +++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/microsetta_admin/server.py b/microsetta_admin/server.py index d023e70..839f0bc 100644 --- a/microsetta_admin/server.py +++ b/microsetta_admin/server.py @@ -629,7 +629,8 @@ def _scan_get(sample_barcode, update_error): update_error=update_error, received_type_dropdown=RECEIVED_TYPE_DROPDOWN, source=result['source'], - events=events + events=events, + observations=result['observations'] ) elif status == 401: # If we fail due to unauthorized, need the user to log in again @@ -655,7 +656,8 @@ def _scan_post_update_info(sample_barcode, issue_type, template, received_type, - recorded_type): + recorded_type, + observations): ### # Bugfix Part 1 for duplicate emails being sent. Theory is that client is @@ -673,13 +675,13 @@ def _scan_post_update_info(sample_barcode, if result['latest_scan']: latest_status = result['latest_scan']['sample_status'] ### - # Do the actual update status, response = APIRequest.post( '/api/admin/scan/%s' % sample_barcode, json={ "sample_status": sample_status, - "technician_notes": technician_notes + "technician_notes": technician_notes, + "observations": observations } ) @@ -763,6 +765,7 @@ def scan(): template = request.form.get('template') received_type = request.form.get('received_type') recorded_type = request.form.get('recorded_type') + observations = request.form.getlist('observations') return _scan_post_update_info(sample_barcode, technician_notes, @@ -771,7 +774,8 @@ def scan(): issue_type, template, received_type, - recorded_type) + recorded_type, + observations) @app.route('/metadata_pulldown', methods=['GET', 'POST']) diff --git a/microsetta_admin/templates/scan.html b/microsetta_admin/templates/scan.html index e5f79b0..5210a04 100644 --- a/microsetta_admin/templates/scan.html +++ b/microsetta_admin/templates/scan.html @@ -247,6 +247,7 @@

Scan History

Scan Timestamp Sample Status Technician Notes + Observations @@ -255,6 +256,7 @@

Scan History

{{ format_timestamp(scan['scan_timestamp']) }} {{ scan['sample_status'] }} {{ scan['technician_notes'] }} + {{ scan['observations'] }} {% endfor %} @@ -305,6 +307,39 @@

Scan History

+ + Sample Observations: + + Tube +
+ {% for observation in observations %} + {% if observation.category == 'Tube' %} + +
+ {% endif %} + {% endfor %} + + Swab +
+ {% for observation in observations %} + {% if observation.category == 'Swab' %} + +
+ {% endif %} + {% endfor %} + + Sample +
+ {% for observation in observations %} + {% if observation.category == 'Sample' %} + +
+ {% endif %} + {% endfor %} + + + + Technician Notes: @@ -353,4 +388,4 @@

Event Log

{% endif %} -{% endblock %} +{% endblock %} \ No newline at end of file From b3ef53f7ad3eb68270e28cc17eb260c332310639 Mon Sep 17 00:00:00 2001 From: ayobi Date: Wed, 5 Jun 2024 03:16:46 -0400 Subject: [PATCH 2/9] changes per suggestions --- microsetta_admin/templates/scan.html | 68 ++++++++++++---------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/microsetta_admin/templates/scan.html b/microsetta_admin/templates/scan.html index 5210a04..ebcbe47 100644 --- a/microsetta_admin/templates/scan.html +++ b/microsetta_admin/templates/scan.html @@ -251,14 +251,18 @@

Scan History

- {% for scan in scans_info %} - - {{ format_timestamp(scan['scan_timestamp']) }} - {{ scan['sample_status'] }} - {{ scan['technician_notes'] }} - {{ scan['observations'] }} - - {% endfor %} + {% for scan in scans_info %} + + {{ format_timestamp(scan['scan_timestamp']) }} + {{ scan['sample_status'] }} + {{ scan['technician_notes'] }} + + {% for observation in scan['observations'] %} + {{ observation }}{% if not loop.last %}, {% endif %} + {% endfor %} + + + {% endfor %} {% else %} @@ -307,39 +311,23 @@

Scan History

- - Sample Observations: - - Tube -
- {% for observation in observations %} - {% if observation.category == 'Tube' %} - -
- {% endif %} - {% endfor %} - - Swab -
- {% for observation in observations %} - {% if observation.category == 'Swab' %} - -
- {% endif %} - {% endfor %} - - Sample -
- {% for observation in observations %} - {% if observation.category == 'Sample' %} - -
- {% endif %} - {% endfor %} - + {% for proj_info in projects_info %} + + Sample Observations: + + {% set unique_categories = observations | selectattr('project_id', 'equalto', proj_info.project_id) | map(attribute='category') | unique %} + {% for category in unique_categories %} + {{ category }}
+ {% for observation in observations if observation.project_id == proj_info.project_id and observation.category == category %} + +
+ {% endfor %} +
+ {% endfor %} + + + {% endfor %} - - Technician Notes: From 73dae538e489d94804f4dcdac0de5714c3b214a6 Mon Sep 17 00:00:00 2001 From: ayobi Date: Fri, 14 Jun 2024 17:28:23 -0400 Subject: [PATCH 3/9] improvements per suggestions --- microsetta_admin/server.py | 52 +++++++++++++++++----------- microsetta_admin/templates/scan.html | 20 +++++------ 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/microsetta_admin/server.py b/microsetta_admin/server.py index 839f0bc..0e16ccd 100644 --- a/microsetta_admin/server.py +++ b/microsetta_admin/server.py @@ -1,5 +1,5 @@ import jwt -from flask import render_template, Flask, request, session, send_file +from flask import render_template, Flask, request, session, send_file, url_for import secrets from datetime import datetime import io @@ -582,10 +582,10 @@ def _check_sample_status(extended_barcode_info): # GET to view the page, # POST to update info for a barcode -AND (possibly)- # email end user about the change in sample status, -def _scan_get(sample_barcode, update_error): +def _scan_get(sample_barcode, update_error, observations): # If there is no sample_barcode in the GET # they still need to enter one in the box, so show empty page - if sample_barcode is None: + if sample_barcode is None and observations is None: return render_template('scan.html', **build_login_variables()) # Assuming there is a sample barcode, grab that sample's information @@ -630,7 +630,7 @@ def _scan_get(sample_barcode, update_error): received_type_dropdown=RECEIVED_TYPE_DROPDOWN, source=result['source'], events=events, - observations=result['observations'] + observations=observations ) elif status == 401: # If we fail due to unauthorized, need the user to log in again @@ -688,13 +688,13 @@ def _scan_post_update_info(sample_barcode, # if the update failed, keep track of the error so it can be displayed if status != 201: update_error = response - return _scan_get(sample_barcode, update_error) + return _scan_get(sample_barcode, update_error, observations) else: update_error = None # If we're not supposed to send an email, go back to GET if action != "send_email": - return _scan_get(sample_barcode, update_error) + return _scan_get(sample_barcode, update_error, observations) ### # Bugfix Part 2 for duplicate emails being sent. @@ -704,7 +704,7 @@ def _scan_post_update_info(sample_barcode, update_error = "Ignoring Send Email, sample_status would " \ "not have been updated (Displayed page was out of " \ "sync)" - return _scan_get(sample_barcode, update_error) + return _scan_get(sample_barcode, update_error, observations) ### # This is what we'll hit if there are no email templates to send for @@ -712,7 +712,7 @@ def _scan_post_update_info(sample_barcode, if template is None: update_error = "Cannot Send Email: No Issue Type Specified " \ "(or no issue types available)" - return _scan_get(sample_barcode, update_error) + return _scan_get(sample_barcode, update_error, observations) # Otherwise, send out an email to the end user status, response = APIRequest.post( @@ -735,7 +735,13 @@ def _scan_post_update_info(sample_barcode, else: update_error = None - return _scan_get(sample_barcode, update_error) + return _scan_get(sample_barcode, update_error, observations) + + +def get_observations(sample_barcode): + status, result = APIRequest.get('/api/admin/scan/observations/%s' + % sample_barcode) + return result @app.route('/scan', methods=['GET', 'POST']) @@ -747,7 +753,10 @@ def scan(): # form parameters if request.method == 'GET': sample_barcode = request.args.get('sample_barcode') - return _scan_get(sample_barcode, None) + observations = get_observations(sample_barcode) + update_error = None + + return _scan_get(sample_barcode, update_error, observations) # If its a post, make the changes, then refresh the page if request.method == 'POST': @@ -765,17 +774,18 @@ def scan(): template = request.form.get('template') received_type = request.form.get('received_type') recorded_type = request.form.get('recorded_type') - observations = request.form.getlist('observations') - - return _scan_post_update_info(sample_barcode, - technician_notes, - sample_status, - action, - issue_type, - template, - received_type, - recorded_type, - observations) + observations = request.form.getlist('observation_id') + + _scan_post_update_info(sample_barcode, + technician_notes, + sample_status, + action, + issue_type, + template, + received_type, + recorded_type, + observations) + return redirect(url_for('scan', sample_barcode=sample_barcode)) @app.route('/metadata_pulldown', methods=['GET', 'POST']) diff --git a/microsetta_admin/templates/scan.html b/microsetta_admin/templates/scan.html index ebcbe47..1d6ff66 100644 --- a/microsetta_admin/templates/scan.html +++ b/microsetta_admin/templates/scan.html @@ -256,11 +256,7 @@

Scan History

{{ format_timestamp(scan['scan_timestamp']) }} {{ scan['sample_status'] }} {{ scan['technician_notes'] }} - - {% for observation in scan['observations'] %} - {{ observation }}{% if not loop.last %}, {% endif %} - {% endfor %} - + {{ scan['observations'] }} {% endfor %} @@ -311,22 +307,22 @@

Scan History

- {% for proj_info in projects_info %} + {% if observations %} - Sample Observations: + Observations: - {% set unique_categories = observations | selectattr('project_id', 'equalto', proj_info.project_id) | map(attribute='category') | unique %} + {% set unique_categories = observations.observation | map(attribute='category') | unique %} {% for category in unique_categories %} {{ category }}
- {% for observation in observations if observation.project_id == proj_info.project_id and observation.category == category %} - -
+ {% for observation in observations.observation if observation.category == category %} + +
{% endfor %}
{% endfor %} - {% endfor %} + {% endif %} Technician Notes: From 1f9c1df2f98deaa44658a368d36249b6a9a8c1d5 Mon Sep 17 00:00:00 2001 From: ayobi Date: Mon, 24 Jun 2024 19:28:20 -0400 Subject: [PATCH 4/9] changes per suggestions --- microsetta_admin/server.py | 24 +++++++++++++++++++++--- microsetta_admin/templates/scan.html | 19 ++++++++++--------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/microsetta_admin/server.py b/microsetta_admin/server.py index 0e16ccd..3b0c79b 100644 --- a/microsetta_admin/server.py +++ b/microsetta_admin/server.py @@ -578,6 +578,21 @@ def _check_sample_status(extended_barcode_info): return warning +def group_observations(scans_info): + grouped_scans = {} + for scan in scans_info: + scan_id = scan['barcode_scan_id'] + if scan_id not in grouped_scans: + grouped_scans[scan_id] = { + 'scan_timestamp': scan['scan_timestamp'], + 'sample_status': scan['sample_status'], + 'technician_notes': scan['technician_notes'], + 'observations': [] + } + grouped_scans[scan_id]['observations'].append(scan['observations']) + return list(grouped_scans.values()) + + # Set up handlers for the cases, # GET to view the page, # POST to update info for a barcode -AND (possibly)- @@ -613,12 +628,14 @@ def _scan_get(sample_barcode, update_error, observations): events = event_result + scans_info = group_observations(result['scans_info']) + return render_template( 'scan.html', **build_login_variables(), barcode_info=result["barcode_info"], projects_info=result['projects_info'], - scans_info=result['scans_info'], + scans_info=scans_info, latest_status=latest_status, dummy_status=DUMMY_SELECT_TEXT, status_options=STATUS_OPTIONS, @@ -753,8 +770,9 @@ def scan(): # form parameters if request.method == 'GET': sample_barcode = request.args.get('sample_barcode') - observations = get_observations(sample_barcode) - update_error = None + if sample_barcode is not None: + observations = get_observations(sample_barcode) + update_error = None return _scan_get(sample_barcode, update_error, observations) diff --git a/microsetta_admin/templates/scan.html b/microsetta_admin/templates/scan.html index 1d6ff66..ed46fd5 100644 --- a/microsetta_admin/templates/scan.html +++ b/microsetta_admin/templates/scan.html @@ -256,7 +256,11 @@

Scan History

{{ format_timestamp(scan['scan_timestamp']) }} {{ scan['sample_status'] }} {{ scan['technician_notes'] }} - {{ scan['observations'] }} + + {% for observation in scan['observations'] %} + {{ observation }}{% if not loop.last %},{% endif %} + {% endfor %} + {% endfor %} @@ -306,19 +310,16 @@

Scan History

+ {{observations}} {% if observations %} Observations: - {% set unique_categories = observations.observation | map(attribute='category') | unique %} - {% for category in unique_categories %} - {{ category }}
- {% for observation in observations.observation if observation.category == category %} - -
- {% endfor %} -
+ {% for observation in observations %} + {{ observation['category'] }}
+ +
{% endfor %} From 601525856e354cf7bd6a18fc7e9bfd9ea8b54805 Mon Sep 17 00:00:00 2001 From: ayobi Date: Tue, 25 Jun 2024 14:23:45 -0400 Subject: [PATCH 5/9] fixed tests --- microsetta_admin/server.py | 5 ++++- microsetta_admin/templates/scan.html | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/microsetta_admin/server.py b/microsetta_admin/server.py index 3b0c79b..07199df 100644 --- a/microsetta_admin/server.py +++ b/microsetta_admin/server.py @@ -770,9 +770,12 @@ def scan(): # form parameters if request.method == 'GET': sample_barcode = request.args.get('sample_barcode') + update_error = None + if sample_barcode is not None: observations = get_observations(sample_barcode) - update_error = None + else: + observations = None return _scan_get(sample_barcode, update_error, observations) diff --git a/microsetta_admin/templates/scan.html b/microsetta_admin/templates/scan.html index ed46fd5..1b008ff 100644 --- a/microsetta_admin/templates/scan.html +++ b/microsetta_admin/templates/scan.html @@ -310,7 +310,6 @@

Scan History

- {{observations}} {% if observations %} From 81783276f8110a45f5cf509d893ad77d1f24045e Mon Sep 17 00:00:00 2001 From: ayobi Date: Tue, 25 Jun 2024 19:19:11 -0400 Subject: [PATCH 6/9] update tests --- microsetta_admin/tests/test_routes.py | 57 ++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/microsetta_admin/tests/test_routes.py b/microsetta_admin/tests/test_routes.py index 43fed19..14cc30b 100644 --- a/microsetta_admin/tests/test_routes.py +++ b/microsetta_admin/tests/test_routes.py @@ -203,9 +203,22 @@ def test_scan_specific_no_warnings(self): "account": {'id': 'd8592c74-9694-2135-e040-8a80115d6401'} } + resp2 = { + "barcode_info": {"barcode": "000004216"}, + "projects_info": [], + "scans_info": [], + "latest_scan": None, + "sample": {'site': 'baz'}, + "source": {'name': 'a source a name', + 'source_type': 'human', + 'source_data': {'description': None}}, + "account": {'id': 'd8592c74-9694-2135-e040-8a80115d6401'} + } + api_get_1 = DummyResponse(200, resp1) - api_get_2 = DummyResponse(200, []) - self.mock_get.side_effect = [api_get_1, api_get_2] + api_get_2 = DummyResponse(200, resp2) + api_get_3 = DummyResponse(200, []) + self.mock_get.side_effect = [api_get_1, api_get_2, api_get_3] response = self.app.get('/scan?sample_barcode=000004216', follow_redirects=True) @@ -232,9 +245,27 @@ def test_scan_specific_no_collection_info_warning(self): 'source_data': {'description': None}}, } + resp2 = { + "barcode_info": {"barcode": "000004216"}, + "projects_info": [{ + "project": "American Gut Project", + "is_microsetta": True, + "bank_samples": False, + "plating_start_date": None + }], + "scans_info": [], + "latest_scan": None, + "sample": {'datetime_collected': None}, + "account": {'id': "ThizIzNotReal"}, + "source": {'name': 'a source a name', + 'source_type': 'human', + 'source_data': {'description': None}}, + } + api_get_1 = DummyResponse(200, resp1) - api_get_2 = DummyResponse(200, []) - self.mock_get.side_effect = [api_get_1, api_get_2] + api_get_2 = DummyResponse(200, resp2) + api_get_3 = DummyResponse(200, []) + self.mock_get.side_effect = [api_get_1, api_get_2, api_get_3] response = self.app.get('/scan?sample_barcode=000004216', follow_redirects=True) @@ -257,9 +288,23 @@ def test_scan_specific_no_associated_source_warning(self): "account": {"id": "foo"}, "source": None} + resp2 = {"barcode_info": {"barcode": "000004216"}, + "projects_info": [{ + "project": "American Gut Project", + "is_microsetta": True, + "bank_samples": False, + "plating_start_date": None + }], + "scans_info": [], + "latest_scan": None, + "sample": None, + "account": {"id": "foo"}, + "source": None} + api_get_1 = DummyResponse(200, resp1) - api_get_2 = DummyResponse(200, []) - self.mock_get.side_effect = [api_get_1, api_get_2] + api_get_2 = DummyResponse(200, resp2) + api_get_3 = DummyResponse(200, []) + self.mock_get.side_effect = [api_get_1, api_get_2, api_get_3] response = self.app.get('/scan?sample_barcode=000004216', follow_redirects=True) From e0d32800823c6ec015c10c1827cbccc9ea883dba Mon Sep 17 00:00:00 2001 From: ayobi Date: Fri, 5 Jul 2024 19:29:12 -0400 Subject: [PATCH 7/9] fixed grouping category, added category to record observations --- microsetta_admin/server.py | 5 ++++- microsetta_admin/templates/scan.html | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/microsetta_admin/server.py b/microsetta_admin/server.py index 07199df..7076822 100644 --- a/microsetta_admin/server.py +++ b/microsetta_admin/server.py @@ -589,7 +589,10 @@ def group_observations(scans_info): 'technician_notes': scan['technician_notes'], 'observations': [] } - grouped_scans[scan_id]['observations'].append(scan['observations']) + grouped_scans[scan_id]['observations'].append({ + 'category': scan['category'], + 'observation': scan['observations'] + }) return list(grouped_scans.values()) diff --git a/microsetta_admin/templates/scan.html b/microsetta_admin/templates/scan.html index 1b008ff..32f3ab1 100644 --- a/microsetta_admin/templates/scan.html +++ b/microsetta_admin/templates/scan.html @@ -258,9 +258,12 @@

Scan History

{{ scan['technician_notes'] }} {% for observation in scan['observations'] %} - {{ observation }}{% if not loop.last %},{% endif %} + {% if observation['category'] %} + {{ observation['category'] }}: {{ observation['observation'] }}{% if not loop.last %}, {% endif %} + {% else %} + {{ observation['observation'] }} + {% endif %} {% endfor %} - {% endfor %} @@ -315,10 +318,13 @@

Scan History

Observations: - {% for observation in observations %} - {{ observation['category'] }}
- -
+ {% set categories = observations|map(attribute='category')|unique %} + {% for category in categories %} + {{ category }}
+ {% for observation in observations if observation['category'] == category %} + +
+ {% endfor %} {% endfor %} From a8b002f8a7b78446970571e762bfa1df8b78c787 Mon Sep 17 00:00:00 2001 From: ayobi Date: Tue, 23 Jul 2024 18:13:48 -0400 Subject: [PATCH 8/9] changed group_observations --- microsetta_admin/server.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/microsetta_admin/server.py b/microsetta_admin/server.py index 7076822..62b3620 100644 --- a/microsetta_admin/server.py +++ b/microsetta_admin/server.py @@ -587,12 +587,8 @@ def group_observations(scans_info): 'scan_timestamp': scan['scan_timestamp'], 'sample_status': scan['sample_status'], 'technician_notes': scan['technician_notes'], - 'observations': [] + 'observations': scan['observations'] } - grouped_scans[scan_id]['observations'].append({ - 'category': scan['category'], - 'observation': scan['observations'] - }) return list(grouped_scans.values()) From 27491cfb69090d0bdaa0527ff64eaa6fc30af4c3 Mon Sep 17 00:00:00 2001 From: ayobi Date: Thu, 25 Jul 2024 15:22:50 -0400 Subject: [PATCH 9/9] removed group_observations --- microsetta_admin/server.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/microsetta_admin/server.py b/microsetta_admin/server.py index 62b3620..c949a29 100644 --- a/microsetta_admin/server.py +++ b/microsetta_admin/server.py @@ -578,20 +578,6 @@ def _check_sample_status(extended_barcode_info): return warning -def group_observations(scans_info): - grouped_scans = {} - for scan in scans_info: - scan_id = scan['barcode_scan_id'] - if scan_id not in grouped_scans: - grouped_scans[scan_id] = { - 'scan_timestamp': scan['scan_timestamp'], - 'sample_status': scan['sample_status'], - 'technician_notes': scan['technician_notes'], - 'observations': scan['observations'] - } - return list(grouped_scans.values()) - - # Set up handlers for the cases, # GET to view the page, # POST to update info for a barcode -AND (possibly)- @@ -627,14 +613,12 @@ def _scan_get(sample_barcode, update_error, observations): events = event_result - scans_info = group_observations(result['scans_info']) - return render_template( 'scan.html', **build_login_variables(), barcode_info=result["barcode_info"], projects_info=result['projects_info'], - scans_info=scans_info, + scans_info=result['scans_info'], latest_status=latest_status, dummy_status=DUMMY_SELECT_TEXT, status_options=STATUS_OPTIONS,