From 51001103ec875b549ad4c1cab227345491978f32 Mon Sep 17 00:00:00 2001 From: anirudhm22 Date: Tue, 24 Mar 2026 01:28:08 +0530 Subject: [PATCH] fix(#356): add session null-check to download endpoints Download endpoints (downloadDataFile, downloadFile, downloadCSVFile, downloadResultsFile, downloadCSV) crashed with TypeError when no case session was set because None was passed to Path(). Now each endpoint validates the session and returns a 400 JSON error if no case is active. --- API/Routes/Case/CaseRoute.py | 2 ++ API/Routes/DataFile/DataFileRoute.py | 18 +++++----- test_issue_356.py | 52 ++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 test_issue_356.py diff --git a/API/Routes/Case/CaseRoute.py b/API/Routes/Case/CaseRoute.py index d95482f41..5750fb276 100644 --- a/API/Routes/Case/CaseRoute.py +++ b/API/Routes/Case/CaseRoute.py @@ -433,6 +433,8 @@ def prepareCSV(): def downloadCSV(): try: casename = session.get('osycase', None) + if not casename: + return jsonify({'message': 'No active case session.', 'status_code': 'error'}), 400 dataFile = Path(Config.DATA_STORAGE,casename,'export.csv') dir = Path(Config.DATA_STORAGE,casename) diff --git a/API/Routes/DataFile/DataFileRoute.py b/API/Routes/DataFile/DataFileRoute.py index 2b7e98eff..dceb7636d 100644 --- a/API/Routes/DataFile/DataFileRoute.py +++ b/API/Routes/DataFile/DataFileRoute.py @@ -160,17 +160,9 @@ def validateInputs(): @datafile_api.route("/downloadDataFile", methods=['GET']) def downloadDataFile(): try: - #casename = request.json['casename'] - #casename = 'DEMO CASE' - # txtFile = DataFile(casename) - # downloadPath = txtFile.downloadDataFile() - # response = { - # "message": "You have downloaded data.txt to "+ str(downloadPath) +"!", - # "status_code": "success" - # } - # return jsonify(response), 200 - #path = "/Examples.pdf" case = session.get('osycase', None) + if not case: + return jsonify({'message': 'No active case session.', 'status_code': 'error'}), 400 caserunname = request.args.get('caserunname') dataFile = Path(Config.DATA_STORAGE,case, 'res',caserunname, 'data.txt') return send_file(dataFile.resolve(), as_attachment=True, max_age=0) @@ -182,6 +174,8 @@ def downloadDataFile(): def downloadFile(): try: case = session.get('osycase', None) + if not case: + return jsonify({'message': 'No active case session.', 'status_code': 'error'}), 400 file = request.args.get('file') dataFile = Path(Config.DATA_STORAGE,case,'res','csv',file) return send_file(dataFile.resolve(), as_attachment=True, max_age=0) @@ -193,6 +187,8 @@ def downloadFile(): def downloadCSVFile(): try: case = session.get('osycase', None) + if not case: + return jsonify({'message': 'No active case session.', 'status_code': 'error'}), 400 file = request.args.get('file') caserunname = request.args.get('caserunname') dataFile = Path(Config.DATA_STORAGE,case,'res',caserunname,'csv',file) @@ -205,6 +201,8 @@ def downloadCSVFile(): def downloadResultsFile(): try: case = session.get('osycase', None) + if not case: + return jsonify({'message': 'No active case session.', 'status_code': 'error'}), 400 caserunname = request.args.get('caserunname') dataFile = Path(Config.DATA_STORAGE,case, 'res', caserunname,'results.txt') return send_file(dataFile.resolve(), as_attachment=True, max_age=0) diff --git a/test_issue_356.py b/test_issue_356.py new file mode 100644 index 000000000..544ff8774 --- /dev/null +++ b/test_issue_356.py @@ -0,0 +1,52 @@ +""" +Test for Issue #356: Download endpoints crash with TypeError when no case session is set. +Verifies that all 5 download endpoints return 400 JSON instead of crashing with TypeError. +""" +import sys +import os + +# Add project root so imports resolve +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'API')) + +from API.app import app + + +def run_tests(): + app.config['TESTING'] = True + client = app.test_client() + + endpoints = [ + ('/downloadDataFile', 'GET', {'caserunname': 'test'}), + ('/downloadFile', 'GET', {'file': 'test.csv'}), + ('/downloadCSVFile', 'GET', {'file': 'test.csv', 'caserunname': 'test'}), + ('/downloadResultsFile', 'GET', {'caserunname': 'test'}), + ('/downloadCSV', 'GET', {}), + ] + + passed = 0 + failed = 0 + + for path, method, params in endpoints: + resp = client.get(path, query_string=params) + + if resp.status_code == 400: + data = resp.get_json() + if data and data.get('status_code') == 'error': + print(f"PASS: {path} -> 400 JSON error") + passed += 1 + else: + print(f"FAIL: {path} -> 400 but unexpected body: {data}") + failed += 1 + elif resp.status_code == 500: + print(f"FAIL: {path} -> 500 (TypeError not fixed!)") + failed += 1 + else: + print(f"FAIL: {path} -> unexpected {resp.status_code}") + failed += 1 + + print(f"\nResults: {passed} passed, {failed} failed out of {len(endpoints)}") + sys.exit(0 if failed == 0 else 1) + + +if __name__ == "__main__": + run_tests()