diff --git a/Dockerfile b/Dockerfile index b04352d..c8b43a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,8 +26,8 @@ RUN pip3 install -r requirements.txt EXPOSE 4000 #debug/dev only -#ENV FLASK_APP SlideServer.py -#CMD python -m flask run --host=0.0.0.0 --port=4000 +# ENV FLASK_APP SlideServer.py +# CMD python -m flask run --host=0.0.0.0 --port=4000 #prod only CMD gunicorn -w 4 -b 0.0.0.0:4000 SlideServer:app --timeout 400 diff --git a/SlideServer.py b/SlideServer.py index 1c87915..7b7ebaf 100644 --- a/SlideServer.py +++ b/SlideServer.py @@ -6,12 +6,18 @@ import string import sys import pyvips +from os import listdir +from os.path import isfile, join + +import urllib import flask import flask_cors import openslide from werkzeug.utils import secure_filename import dev_utils +import requests + try: from io import BytesIO @@ -27,7 +33,7 @@ app.config['TOKEN_SIZE'] = 10 app.config['SECRET_KEY'] = os.urandom(24) -ALLOWED_EXTENSIONS = set(['svs', 'tif', 'tiff', 'vms', 'vmu', 'ndpi', 'scn', 'mrxs', 'bif', 'svslide']) +ALLOWED_EXTENSIONS = set(['svs', 'tif', 'tiff', 'vms', 'vmu', 'ndpi', 'scn', 'mrxs', 'bif', 'svslide']) def allowed_file(filename): @@ -130,6 +136,29 @@ def finish_upload(token): # get info associated with token # move the file out of temp to upload dir +# Delete the requested slide +@app.route('/slide/delete', methods=['POST']) +def slide_delete(): + body = flask.request.get_json() + + if not body: + return flask.Response(json.dumps({"error": "Missing JSON body"}), status=400) + + filename = body['filename'] + if filename and allowed_file(filename): + filename = secure_filename(filename) + filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) + if os.path.isfile(filepath): + os.remove(os.path.join(app.config['UPLOAD_FOLDER'], filename)) + return flask.Response(json.dumps({"deleted": filename, "success": True})) + else: + return flask.Response(json.dumps({"error": "File with name '" + filename + "' does not exist"}), status=400) + + else: + return flask.Response(json.dumps({"error": "Invalid filename"}), status=400) + + # check for file if it exists or not + # delete the file @app.route("/test", methods=['GET']) def testRoute(): @@ -150,3 +179,49 @@ def singleThumb(filepath): @app.route("/data/many/", methods=['GET']) def multiSlide(filepathlist): return json.dumps(dev_utils.getMetadataList(json.loads(filepathlist), app.config['UPLOAD_FOLDER'])) + + +@app.route("/getSlide/") +def getSlide(image_name): + if(os.path.isfile("/images/"+image_name)): + return flask.send_from_directory(app.config["UPLOAD_FOLDER"], filename=image_name, as_attachment=True) + else: + return flask.Response(json.dumps({"error": "File does not exist"}), status=404) + +# using the token from the start url upload endpoint +@app.route('/urlupload/continue/', methods=['POST']) +def continue_urlfile(token): + token = secure_filename(token) + tmppath = os.path.join(app.config['TEMP_FOLDER'], token) + if os.path.isfile(tmppath): + body = flask.request.get_json() + if not body: + return flask.Response(json.dumps({"error": "Missing JSON body"}), status=400) + if not 'url' in body: + return flask.Response(json.dumps({"error": "File url not present in body"}), status=400) + else: + url = body['url'] + try: + url = urllib.parse.unquote(url) + urllib.request.urlretrieve(url, tmppath) + return flask.Response(json.dumps({"status": "OK Uploaded"}), status=200) + except: + return flask.Response(json.dumps({"error": "URL invalid"}), status=400) + else: + return flask.Response(json.dumps({"error": "Token Not Recognised"}), status=400) + +# Route to check if the URL file has completely uploaded to the server +# Query Params: 'url', 'token' +@app.route('/urlupload/check', methods=['GET']) +def urlUploadStatus(): + url = flask.request.args.get('url') + url = urllib.parse.unquote(url) + token = flask.request.args.get('token') + info = requests.head(url) + urlFileSize = int(info.headers['Content-Length']) + fileSize = os.path.getsize(app.config['TEMP_FOLDER']+'/'+token) + if(fileSize >= urlFileSize): + return flask.Response(json.dumps({"uploaded": "True"}), status=200) + else: + return flask.Response(json.dumps({"uploaded": "False"}), status=200) + diff --git a/dev_utils.py b/dev_utils.py index eddf32b..4b47a7f 100644 --- a/dev_utils.py +++ b/dev_utils.py @@ -34,8 +34,10 @@ def getMetadata(filename, upload_folder): "openslide.level[0].width", None) metadata['vendor'] = slideData.get(openslide.PROPERTY_NAME_VENDOR, None) metadata['level_count'] = int(slideData.get('level_count', 1)) - metadata['objective'] = float(slideData.get("aperio.AppMag", -1.0)) + metadata['objective'] = float(slideData.get(openslide.PROPERTY_NAME_OBJECTIVE_POWER, 0) or + slideData.get("aperio.AppMag", -1.0)) metadata['md5sum'] = file_md5(filepath) + metadata['comment'] = slideData.get(openslide.PROPERTY_NAME_COMMENT, None) metadata['study'] = "" metadata['specimen'] = "" return metadata diff --git a/requirements.txt b/requirements.txt index 823b15e..3c43dc0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ openslide-python flask Werkzeug flask-cors -requests \ No newline at end of file +requests