https://forgemia.inra.fr/asterics/asterics
Tip revision: f56b151c66529b4bada418ade342fd76d1199c70 authored by Nathalie Vialaneix on 07 November 2022, 10:27:35 UTC
Merge branch 'dev-pls_inherit' into 'dev'
Merge branch 'dev-pls_inherit' into 'dev'
Tip revision: f56b151
asterics.py
from email import utils
import os
import json
import re
import socket
from flask import Flask, abort, render_template, jsonify, request, send_from_directory
from flask_uuid import FlaskUUID
from flask_mail import Mail
from pyRserve.rexceptions import RConnectionRefused, REvalError
from backend.asterics.workspace import Workspace
from backend.asterics.rsessionshandler import RSessionsHandler
from backend.asterics.rsession import SessionInUse
from backend.asterics.utils import sendEmail, formatFileSize
from flask_cors import CORS
app = Flask(__name__,
static_folder = "./dist/static",
template_folder = "./dist")
app.config.from_pyfile('application.cfg', silent=False)
FlaskUUID(app)
app.mail = Mail(app)
app.rsessions = RSessionsHandler()
if (app.env == "development") :
cors = CORS(app)
@app.errorhandler(400)
def r_execution_error(e):
return jsonify(error=str(e)), 400
@app.errorhandler(503)
def r_session_error(e):
return jsonify(error=str(e)), 503
@app.route('/api/run_r_function', methods=['GET', 'POST'])
def run_r_function() :
try:
uuid = request.json.pop('uuid')
workspace = Workspace.get_workspace(uuid)
return workspace.run_r_function(**request.json)
except (SessionInUse) as err:
abort(503, description=err)
except (IOError, REvalError, RConnectionRefused) as err:
abort(400, description=err)
@app.route('/api/get_rsessions', methods=['GET', 'POST'])
def get_rsessions():
if (app.env == "development"):
try:
all_keys = app.rsessions.get_sessions_keys()
all_sessions = []
for key in all_keys:
session = app.rsessions.get_session(key)
all_sessions.append({
'uuid': key,
'content': session.get_content()
})
return jsonify(all_sessions)
except (SessionInUse) as err:
abort(503, description=err)
except (IOError, REvalError, RConnectionRefused) as err:
abort(400, description=err)
else :
abort(404, description="Sessions list not available!")
@app.route('/api/add_dataset', methods=['POST'])
def add_dataset():
try:
uuid = request.form['uuid']
dataset = json.loads(request.files['dataset'].read().decode('utf-8'))
iparameters = json.loads(request.files['parameters'].read().decode('utf-8'))
cworkspace = Workspace.get_workspace(uuid)
return cworkspace.add_dataset(request.files['file'], dataset, iparameters)
except (SessionInUse) as err:
abort(503, description=err)
except (IOError, REvalError, RConnectionRefused) as err:
abort(400, description=err)
@app.route('/api/load_demo_datasets', methods=['POST'])
def load_demo_datasets():
try:
uuid = request.json.pop('uuid')
cworkspace = Workspace.get_workspace(uuid)
data_dir= os.path.join (os.path.split(app.instance_path)[0],"data","demo")
dataset={'id': None, 'name': 'mrna', 'nature': 'rna-count', 'status': 'dataset', 'parent': []}
iparameters={'nature': 'microarray', 'header': True, 'sep': ',', 'quote': '"', 'dec': '.', 'transpose': False, 'encoding': 'unknown', 'na.strings': ['NA'], 'out_graph': True, 'row.names': 1, 'logt': 'yes', 'normalized': 'yes'}
cworkspace.add_dataset(os.path.join(data_dir,"mrna.csv"), dataset, iparameters)
dataset={'id': None, 'name': 'protein', 'nature': 'generic', 'status': 'dataset', 'parent': []}
iparameters={'nature': 'generic', 'header': True, 'sep': ' ', 'quote': '"', 'dec': '.', 'transpose': False, 'encoding': 'unknown', 'na.strings': ['NA'], 'out_graph': True, 'row.names': 1}
cworkspace.add_dataset(os.path.join(data_dir,"protein.csv"), dataset, iparameters)
dataset={'id': None, 'name': 'clinical', 'nature': 'metadata', 'status': 'dataset', 'parent': []}
iparameters={'nature': 'metadata', 'header': True, 'sep': ',', 'quote': '"', 'dec': '.', 'transpose': False, 'encoding': 'unknown', 'na.strings': ['NA'], 'out_graph': True, 'row.names': 1}
return cworkspace.add_dataset(os.path.join(data_dir,"clinical.csv"), dataset, iparameters)
except (SessionInUse) as err:
abort(503, description=err)
except (IOError, REvalError, RConnectionRefused) as err:
abort(400, description=err)
@app.route('/api/get_remaining_days', methods=['GET', 'POST'])
def get_remaining_days():
uuid = request.json['uuid']
workspace = Workspace.get_workspace(uuid)
return { 'remainingDays': workspace.getRemainingDays() }
@app.route('/api/close_workspace', methods=['GET', 'POST'])
def close_workspace():
if (app.env != "development"):
uuid = request.json['uuid']
cworkspace = Workspace.get_workspace(uuid)
cworkspace.close()
return { 'close': True }
@app.route('/api/get_workspace_uuids', methods=['GET', 'POST'])
def get_workspace_uuids():
return { 'uuids': Workspace.get_workspace_uuids() }
@app.route('/api/get_metadata', methods=['GET', 'POST'])
def get_metadata():
#convert in Byte
m = m=re.search('(\d+)\s?(\S*)$', app.config['FILE_SIZE_LIMIT'])
size_value = int (m.groups()[0] )
if size_value > 0 :
size_value = formatFileSize(size_value, m.groups()[1],'B')
return { 'contact': app.config['CONTACT_EMAIL'] ,
'report_bug_url' : app.config['REPORT_BUG_URL'] ,
'source_version' : app.config['SOURCE_VERSION'] ,
'copyright_year' : app.config['COPYRIGHT_YEAR'] ,
'file_size_limit' : size_value}
@app.route('/api/create_workspace', methods=['GET', 'POST'])
def create_workspace():
uuid = request.json['uuid']
email = request.json['email']
url = request.json['url']
# Create workspace
Workspace.create_workspace(uuid, email)
# Send email to user
body = '''Dear user,
Your workspace has been successfully created at {}{}.
Thank you for using ASTERICS,
The ASTERICS Team
'''.format(url,uuid)
sendEmail('Workspace created', body, [email])
return {}
#Function to secure
def remote_addr_is_local():
# Retrieve serveur IP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
trusted_proxies = (s.getsockname()[0],'127.0.0.1')
#Retrieve user IP
route = list(request.access_route)
for ip in route :
if ip in trusted_proxies:
return True
return False
@app.route('/api/close_old_session', methods=['GET', 'POST'])
def close_old_session():
#To be tested on server
if remote_addr_is_local() :
all_keys = app.rsessions.get_sessions_keys()
for key in all_keys:
workspace = Workspace.get_workspace(key,mode="control")
#if last connexion delay is 1 day
if workspace.getDelayLastConnection()>= 0 :
app.rsessions.close_session(key)
else :
abort(405, description="Not allowed!")
return {}
@app.route('/api/get_file')
def get_file():
secure_store_dir = app.config['STORAGE_DIR']
file = request.args.get('file')
(head, tail) = os.path.split(file)
if (file.startswith(secure_store_dir)):
if file.endswith(".png"):
#TDO test id haed starts with : secure_store_dir
return send_from_directory(head, tail, mimetype='image/PNG', as_attachment=True)
else:
return send_from_directory(head, tail, as_attachment=True)
else:
abort(405, description="Path not allowed!")
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
@app.route('/<path:path>/<uuid:uid>')
def catch_all(path, uid=None):
#requests.get('http://localhost:8080/{}'.format(path)).text
return render_template("index.html")
if __name__ == "__main__":
app.run()