web_app.py 7.23 KB
Newer Older
carignani's avatar
carignani committed
#!/bin/python3
carignani's avatar
carignani committed
'''
Web app to offer a frontend to the doc2tosca and tosca2doc tools

'''
carignani's avatar
carignani committed

import os
carignani's avatar
carignani committed
import shutil
import tempfile
import logging
import traceback
carignani's avatar
carignani committed
from zipfile import ZipFile
carignani's avatar
carignani committed

carignani's avatar
carignani committed
from flask import Flask, flash, request, redirect, send_file, render_template, g
carignani's avatar
carignani committed
from werkzeug.utils import secure_filename
import docx
carignani's avatar
carignani committed

import config
carignani's avatar
carignani committed
import tosca2doc
carignani's avatar
carignani committed
import doc2tosca
carignani's avatar
carignani committed

class ReverseProxied(object):

carignani's avatar
carignani committed
    def __init__(self, the_app, script_name=None, scheme=None, server=None):
        self.app = the_app
        self.script_name = script_name
        self.scheme = scheme
        self.server = server

    def __call__(self, environ, start_response):
        script_name = environ.get('HTTP_X_SCRIPT_NAME', '') or self.script_name
        if script_name:
            environ['SCRIPT_NAME'] = script_name
            path_info = environ['PATH_INFO']
            if path_info.startswith(script_name):
                environ['PATH_INFO'] = path_info[len(script_name):]
        scheme = environ.get('HTTP_X_SCHEME', '') or self.scheme
        if scheme:
            environ['wsgi.url_scheme'] = scheme
        server = environ.get('HTTP_X_FORWARDED_HOST', '') or self.server
        if server:
            environ['HTTP_HOST'] = server
        return self.app(environ, start_response)

app = Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app, script_name='/tosca-ie')
carignani's avatar
carignani committed
UPLOAD_FOLDER = '/tmp/upload'

ALLOWED_EXTENSIONS = set(['txt', 'yaml', 'docx'])

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
carignani's avatar
carignani committed
app.secret_key = config.SECRET
carignani's avatar
carignani committed
app.config['SESSION_TYPE'] = 'filesystem'

carignani's avatar
carignani committed
TOSCA_DEFS = ['VNFD', 'NSD', 'PNFD']
carignani's avatar
carignani committed

carignani's avatar
carignani committed
MISSING_MODULE_ERR_MSG = \
    'Error: some TOSCA module missing. Make sure to \
    upload definitions for NSD, VNFD, PNFD.'

carignani's avatar
carignani committed
def allowed_file(filename):
    '''
    Check filename is in the list of allowed extensions
    '''
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

carignani's avatar
carignani committed
@app.route("/")
def hello():
carignani's avatar
carignani committed
    '''
    Render home page
    '''
    if config.LAST_COMMIT is not False:
        link = config.REPO_URL+config.LAST_COMMIT.split(" ")[0]
    else:
        link = "#"

carignani's avatar
carignani committed
    return render_template(
        "./home.html",
        VERSION=config.VERSION,
        doc_allowed_versions=doc2tosca.allowed_versions,
        default_tosca_version=doc2tosca.DEFAULT_TOSCA_VERSION,
        last_rev=config.LAST_COMMIT,
        rev_link=link
carignani's avatar
carignani committed
    )
carignani's avatar
carignani committed

carignani's avatar
carignani committed
@app.route("/doc2tosca-info")
def doc2tosca_info():
    '''
    Render home page
    '''
    return render_template("./doc2tosca-details.html", VERSION=config.VERSION)

carignani's avatar
carignani committed
@app.route("/tosca2doc-info")
def tosca2doc_info():
    '''
    Render home page
    '''
    return render_template("./tosca2doc-details.html", VERSION=config.VERSION)

carignani's avatar
carignani committed
@app.route("/tosca2doc", methods=['POST'])
def mk_tosca2doc():
carignani's avatar
carignani committed
    '''
    Execute tosca2doc on the uploaded files
    '''
carignani's avatar
carignani committed

    if 'file' not in request.files:
        flash('Error: No file uploaded.')
        return redirect("/tosca-ie")
carignani's avatar
carignani committed

    ufiles = request.files.getlist("file")
carignani's avatar
carignani committed

    for tosca_def in TOSCA_DEFS:
        found = False
carignani's avatar
carignani committed
        for uploaded_file in ufiles:
            if tosca_def in uploaded_file.filename or \
               tosca_def.lower() in uploaded_file.filename:
                found = True
carignani's avatar
carignani committed
        if not found:
carignani's avatar
carignani committed
            flash(MISSING_MODULE_ERR_MSG)
            print('Error: TOSCA module missing.')
            return redirect("/tosca-ie")
carignani's avatar
carignani committed

    for file in ufiles:
        if file.filename == '':
            print('Error: No selected file')
            flash('Error: No file uploaded or wrong name.')
            return redirect("/tosca-ie")
carignani's avatar
carignani committed

carignani's avatar
carignani committed
    tmp_dir = tempfile.mkdtemp()
    g.tmp_dir = tmp_dir

    doc = docx.Document()
carignani's avatar
carignani committed

    for tosca_def in TOSCA_DEFS:
        for file in ufiles:
            if tosca_def in uploaded_file.filename or \
                tosca_def.lower() in uploaded_file.filename:
                filename = secure_filename(file.filename)
                filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
                file.save(filepath)
                file.close()

                tosca2doc.generate_from_file(tosca_def, doc, filepath)

carignani's avatar
carignani committed
    outfilename = os.path.join(tmp_dir, 'myfile.docx')

    doc.save(outfilename)
    return send_file(outfilename)
carignani's avatar
carignani committed

carignani's avatar
carignani committed
    #return ("No content found")


def get_all_yaml_file_paths_and_logs(directory):
carignani's avatar
carignani committed
    '''
    Finds yaml files within a directory and sub directories and
    returns the list of paths
    '''
carignani's avatar
carignani committed

    file_paths = []

carignani's avatar
carignani committed
    for root, _, files in os.walk(directory):
carignani's avatar
carignani committed
        for filename in files:
            if ".yaml" in filename or ".log" in filename:
carignani's avatar
carignani committed
                filepath = os.path.join(root, filename)
                file_paths.append(filepath)

    return file_paths

carignani's avatar
carignani committed
@app.after_request
def after_request(response):
carignani's avatar
carignani committed
    '''
    Clean up files created by doc2tosca
    '''
carignani's avatar
carignani committed
    if request.path != '/doc2tosca':
        return response
carignani's avatar
carignani committed
    if g.get('tmp_dir') is None:
        return response
carignani's avatar
carignani committed
    shutil.rmtree(g.tmp_dir, ignore_errors=True)
    logging.debug("Deleted {}\n\n".format(g.tmp_dir))
carignani's avatar
carignani committed
    return response

carignani's avatar
carignani committed
@app.route("/doc2tosca", methods=['POST'])
def mk_doc2tosca():
carignani's avatar
carignani committed
    '''
    Executes doc2tosca on the uploaded file
    '''
    tmp_dir = tempfile.mkdtemp()

    logfilename = os.path.join(tmp_dir, 'toscatools.log')
    logging.basicConfig(filename=logfilename, level=logging.INFO)

    logging.info("Starting")
    logging.debug("TMP DIR: " + tmp_dir)

carignani's avatar
carignani committed
    zip_fn = "tosca_defs.zip"
    zip_path = os.path.join(tmp_dir, zip_fn)
carignani's avatar
carignani committed

    if 'file' not in request.files:
        flash('No file uploaded')
        return redirect("/tosca-ie")
carignani's avatar
carignani committed

    ufiles = request.files.getlist("file")

        logging.debug(request.form)
        doc_version = request.form.get('doc-version')
        custom_doc_version = request.form.get('custom-doc-version')
        custom_tosca_version = request.form.get('custom-tosca-version')
carignani's avatar
carignani committed
        yaml_root_path = request.form.get('yaml-root-path')
    except:
        flash("Something went wrong :/")
        return redirect("/tosca-ie")

    if doc_version not in doc2tosca.allowed_versions:
        flash('Incorrect doc version selected')
        return redirect("/tosca-ie")

carignani's avatar
carignani committed
    sol001_file = ufiles[0]

    tosca_version = doc2tosca.DEFAULT_TOSCA_VERSION

    if custom_doc_version != "":
        doc_version = custom_doc_version

    if custom_tosca_version != "":
        tosca_version = custom_tosca_version

        doc2tosca.generate_templates(
            sol001_file, doc_version, yaml_root_path, tosca_version
        )
        doc2tosca.print_to_files(tmp_dir)

    except ValueError as e:
        flash(str(e))
        return redirect("/tosca-ie")
    except BaseException as e:
        print(e)
        # logging.error(traceback.print_exc())
        flash("Unknown error in the generation of the files. \
               Please contact the support.")
    finally:
        file_paths = get_all_yaml_file_paths_and_logs(tmp_dir)
        with ZipFile(zip_path, 'w') as archive:
            for myfile in file_paths:
                print(myfile)
                logging.info(myfile)
                archive.write(myfile, arcname=os.path.basename(myfile))
        g.tmp_dir = tmp_dir
        return send_file(zip_path, as_attachment=True)
carignani's avatar
carignani committed

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')