Skip to content
Closed
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
5 changes: 5 additions & 0 deletions API/Classes/Base/Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ def validate_path(base_dir, user_input):
BASE_DIR = Path(__file__).resolve().parents[3]

WEBAPP_PATH = BASE_DIR / "WebAPP"
API_PATH = BASE_DIR / "API"

# Log file in a safe location (not under WebAPP, to avoid serving logs to clients).
# Upstream v5.5 uses WebAPP/app.log which we explicitly reject (see #390).
LOG_FILE = API_PATH / "app.log"

UPLOAD_FOLDER = WEBAPP_PATH
DATA_STORAGE = WEBAPP_PATH / "DataStorage"
Expand Down
45 changes: 36 additions & 9 deletions API/Routes/DataFile/DataFileRoute.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from flask import Blueprint, jsonify, request, send_file, session
from flask import Blueprint, Response, jsonify, request, send_file, session
from pathlib import Path
import shutil, datetime, time, os
import shutil, datetime, time, os, logging
from Classes.Case.DataFileClass import DataFile
from Classes.Base import Config

logger = logging.getLogger(__name__)

datafile_api = Blueprint('DataFileRoute', __name__)

@datafile_api.route("/generateDataFile", methods=['POST'])
Expand Down Expand Up @@ -141,7 +143,30 @@ def readDataFile():
return jsonify(response), 200
except(IOError):
return jsonify('No existing cases!'), 404


@datafile_api.route("/readModelFile", methods=['GET'])
def readModelFile():
"""Return the OSeMOSYS model text file as plain text (v5.5 diagnostic feature)."""
try:
model_path = Path(Config.SOLVERs_FOLDER, 'model.v.5.4.txt')
text = model_path.read_text(encoding="utf-8", errors="replace")
return Response(text, mimetype="text/plain; charset=utf-8")
except IOError:
return jsonify('Model file not found!'), 404

@datafile_api.route("/readLogFile", methods=['GET'])
def readLogFile():
"""Return the application log as plain text (v5.5 diagnostic feature).

MUIOGO-safe: reads from Config.LOG_FILE (API/app.log), NOT from WebAPP/
as upstream does, to avoid exposing logs from the web root.
"""
try:
text = Config.LOG_FILE.read_text(encoding="utf-8", errors="replace")
return Response(text, mimetype="text/plain; charset=utf-8")
except IOError:
return jsonify('Log file not found!'), 404

@datafile_api.route("/validateInputs", methods=['POST'])
def validateInputs():
try:
Expand Down Expand Up @@ -218,13 +243,11 @@ def run():
casename = request.json['casename']
caserunname = request.json['caserunname']
solver = request.json['solver']
logger.info("Starting optimization process for model -- %s -- caserun -- %s --!", casename, caserunname)
txtFile = DataFile(casename)
response = txtFile.run(solver, caserunname)
response = txtFile.run(solver, caserunname)
logger.info("Optimization finished for model -- %s -- caserun -- %s --!", casename, caserunname)
return jsonify(response), 200
# except Exception as ex:
# print(ex)
# return ex, 404

except(IOError):
return jsonify('No existing cases!'), 404

Expand All @@ -238,7 +261,9 @@ def batchRun():
if modelname != None:
txtFile = DataFile(modelname)
for caserun in cases:
logger.info("Data file generation process started for model %s caserun %s!", modelname, caserun)
txtFile.generateDatafile(caserun)
logger.info("Data file generation process finished for model %s caserun %s!", modelname, caserun)

response = txtFile.batchRun( 'CBC', cases)
end = time.time()
Expand All @@ -254,7 +279,9 @@ def cleanUp():

if modelname != None:
model = DataFile(modelname)
response = model.cleanUp()
logger.info("Clean up process started!")
response = model.cleanUp()
logger.info("Clean up process finished!")

return jsonify(response), 200
except(IOError):
Expand Down
Loading