main.py 7.27 KB
Newer Older
1
2
#!/usr/bin/env python3

Floreal Cabanettes's avatar
Floreal Cabanettes committed
3
import os
4
5
import time
import datetime
6
import shutil
7
import re
8
from flask import Flask, render_template, request, url_for, jsonify, session
9
from flask_mail import Mail
10
from lib.paf import Paf
11
from config_reader import AppConfigReader
12
from lib.job_manager import JobManager
13
from lib.functions import Functions, ALLOWED_EXTENSIONS
14
from lib.upload_file import UploadFile
15
from lib.Fasta import Fasta
16
17

import sys
18

19
20
21
22
23
24
app_folder = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, app_folder)
os.environ["PATH"] = os.path.join(app_folder, "bin") + ":" + os.environ["PATH"]

sqlite_file = os.path.join(app_folder, "database.sqlite")

25
26
27
28

# Init config reader:
config_reader = AppConfigReader()

29
30
UPLOAD_FOLDER = config_reader.get_upload_folder()

Floreal Cabanettes's avatar
Floreal Cabanettes committed
31
app_title = "D-GENIES - Dotplot for Genomes Interactive, E-connected and Speedy"
Floreal Cabanettes's avatar
Floreal Cabanettes committed
32

33
# Init Flask:
34
app = Flask(__name__, static_url_path='/static')
35
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
36
app.config['SECRET_KEY'] = 'dsqdsq-255sdA-fHfg52-25Asd5'
37

38
39
40
# Init mail:
mail = Mail(app)

41
# Folder containing data:
42
43
44
app_data = config_reader.get_app_data()


Floreal Cabanettes's avatar
Floreal Cabanettes committed
45
46
47
48
49
50
@app.context_processor
def get_launched_results():
    cookie = request.cookies.get("results")
    return {"results": cookie.split("|") if cookie is not None else set()}


51
52
53
# Main
@app.route("/", methods=['GET'])
def main():
Floreal Cabanettes's avatar
Floreal Cabanettes committed
54
55
56
57
58
    return render_template("index.html", title=app_title, menu="index")


@app.route("/run", methods=['GET'])
def run():
Floreal Cabanettes's avatar
Floreal Cabanettes committed
59
    session["user_tmp_dir"] = Functions.random_string(5) + "_" + \
60
                              datetime.datetime.fromtimestamp(time.time()).strftime('%Y%m%d%H%M%S')
Floreal Cabanettes's avatar
Floreal Cabanettes committed
61
    id_job = Functions.random_string(5) + "_" + datetime.datetime.fromtimestamp(time.time()).strftime('%Y%m%d%H%M%S')
62
63
64
65
66
    if "id_job" in request.args:
        id_job = request.args["id_job"]
    email = ""
    if "email" in request.args:
        email = request.args["email"]
Floreal Cabanettes's avatar
Floreal Cabanettes committed
67
    return render_template("run.html", title=app_title, id_job=id_job, email=email,
68
                           menu="run", allowed_ext=ALLOWED_EXTENSIONS)
69
70
71
72
73
74
75


# Launch analysis
@app.route("/launch_analysis", methods=['POST'])
def launch_analysis():
    id_job = request.form["id_job"]
    email = request.form["email"]
76
77
78
79
    file_query = request.form["query"]
    file_query_type = request.form["query_type"]
    file_target = request.form["target"]
    file_target_type = request.form["target_type"]
80
81
82

    # Check form:
    form_pass = True
83
    errors = []
84
    if id_job == "":
85
        errors.append("Id of job not given")
86
87
88
        form_pass = False

    if email == "":
89
        errors.append("Email not given")
90
        form_pass = False
91
92
    if file_query == "":
        errors.append("No query fasta selected")
93
94
95
96
        form_pass = False

    # Form pass
    if form_pass:
97
        # Get final job id:
98
        id_job = re.sub('[^A-Za-z0-9_\-]+', '', id_job.replace(" ", "_"))
99
100
101
102
103
104
105
106
        id_job_orig = id_job
        while os.path.exists(os.path.join(app_data, id_job)):
            id_job = id_job_orig + "_2"

        folder_files = os.path.join(app_data, id_job)
        os.makedirs(folder_files)

        # Save files:
107
108
109
        query_name = os.path.splitext(file_query.replace(".gz", ""))[0] if file_query_type == "local" else None
        query_path = os.path.join(app.config["UPLOAD_FOLDER"], session["user_tmp_dir"], file_query) \
            if file_query_type == "local" else file_query
110
111
112
        query = Fasta(name=query_name, path=query_path, type_f=file_query_type)
        target = None
        if file_target != "":
113
114
115
            target_name = os.path.splitext(file_target.replace(".gz", ""))[0] if file_target_type == "local" else None
            target_path = os.path.join(app.config["UPLOAD_FOLDER"], session["user_tmp_dir"], file_target) \
                if file_target_type == "local" else file_target
116
117
118
            target = Fasta(name=target_name, path=target_path, type_f=file_target_type)

        # Launch job:
Floreal Cabanettes's avatar
Floreal Cabanettes committed
119
        job = JobManager(id_job, email, query, target, app, mail)
120
121
        job.launch()
        return jsonify({"success": True, "redirect": url_for(".status", id_job=id_job)})
122
    else:
123
        return jsonify({"success": False, "errors": errors})
124
125
126
127
128
129


# Status of a job
@app.route('/status/<id_job>', methods=['GET'])
def status(id_job):
    job = JobManager(id_job)
130
131
    j_status, error = job.status()
    return render_template("status.html", title=app_title, status=j_status, error=error, id_job=id_job,
Floreal Cabanettes's avatar
Floreal Cabanettes committed
132
                           menu="results")
133
134


Floreal Cabanettes's avatar
Floreal Cabanettes committed
135
# Results path
136
@app.route("/result/<id_res>", methods=['GET'])
137
def result(id_res):
Floreal Cabanettes's avatar
Floreal Cabanettes committed
138
139
140
141
142
143
144
145
    my_render = render_template("results.html", title=app_title, id=id_res, menu="results", current_result=id_res)
    response = app.make_response(my_render)
    cookie = request.cookies.get("results")
    cookie = cookie.split("|") if cookie is not None else []
    if id_res not in cookie:
        cookie.insert(0, id_res)
    response.set_cookie(key="results", value="|".join(cookie), path="/")
    return response
146
147


Floreal Cabanettes's avatar
Floreal Cabanettes committed
148
# Get graph (ajax request)
149
150
151
@app.route('/get_graph', methods=['POST'])
def get_graph():
    id_f = request.form["id"]
152
    paf = os.path.join(app_data, id_f, "map.paf")
153
154
    idx1 = os.path.join(app_data, id_f, "query.idx")
    idx2 = os.path.join(app_data, id_f, "target.idx")
155

156
    paf = Paf(paf, idx1, idx2)
157

158
159
    if paf.parsed:
        res = paf.get_d3js_data()
160
        res["success"] = True
161
162
163
164
165
166
        return jsonify(res)
    return jsonify({"success": False, "message": paf.error})


@app.route('/sort/<id_res>', methods=['POST'])
def sort_graph(id_res):
Floreal Cabanettes's avatar
Floreal Cabanettes committed
167
168
169
    paf = os.path.join(app_data, id_res, "map.paf")
    idx1 = os.path.join(app_data, id_res, "query.idx")
    idx2 = os.path.join(app_data, id_res, "target.idx")
170
    paf = Paf(paf, idx1, idx2, False)
Floreal Cabanettes's avatar
Floreal Cabanettes committed
171
172
173
174
175
176
177
    paf.sort()
    if paf.parsed:
        res = paf.get_d3js_data()
        res["success"] = True
        return jsonify(res)
    return jsonify({"success": False, "message": paf.error})

Floréal Cabanettes's avatar
Floréal Cabanettes committed
178

179
180
@app.route("/upload", methods=['POST'])
def upload():
181
182
183
184
185
186
187
188
189
    if "user_tmp_dir" in session and session["user_tmp_dir"] != "":
        folder = session["user_tmp_dir"]
        files = request.files[list(request.files.keys())[0]]

        if files:
            filename = files.filename
            folder_files = os.path.join(app.config["UPLOAD_FOLDER"], folder)
            if not os.path.exists(folder_files):
                os.makedirs(folder_files)
Floreal Cabanettes's avatar
Floreal Cabanettes committed
190
            filename = Functions.get_valid_uploaded_filename(filename, folder_files)
191
192
            mime_type = files.content_type

Floreal Cabanettes's avatar
Floreal Cabanettes committed
193
            if not Functions.allowed_file(files.filename):
194
                result = UploadFile(name=filename, type_f=mime_type, size=0, not_allowed_msg="File type not allowed")
195
                shutil.rmtree(folder_files)
196
197
198
199
200
201
202
203
204
205

            else:
                # save file to disk
                uploaded_file_path = os.path.join(folder_files, filename)
                files.save(uploaded_file_path)

                # get file size after saving
                size = os.path.getsize(uploaded_file_path)

                # return json for js call back
206
                result = UploadFile(name=filename, type_f=mime_type, size=size)
207
208
209
210
211

            return jsonify({"files": [result.get_file()], "success": "OK"})

        return jsonify({"files": [], "success": "404", "message": "No file provided"})
    return jsonify({"files": [], "success": "ERR", "message": "Session not initialized. Please refresh the page."})
212
213


Floréal Cabanettes's avatar
Floréal Cabanettes committed
214
215
if __name__ == '__main__':
    app.run()