From 4ab1bfecb38c0bff022adb982820e681fb8053bd Mon Sep 17 00:00:00 2001
From: Michele Carignani <michele.carignani@etsi.org>
Date: Thu, 7 Mar 2019 10:17:27 +0100
Subject: [PATCH] prototype of webapp

---
 tosca2doc.py | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++
 web_app.py   |  94 +++++++++++++++++++++++++
 2 files changed, 286 insertions(+)
 create mode 100755 tosca2doc.py
 create mode 100644 web_app.py

diff --git a/tosca2doc.py b/tosca2doc.py
new file mode 100755
index 0000000..475b123
--- /dev/null
+++ b/tosca2doc.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python2.7
+'''
+Parses a TOSCA template and generates a docx file
+'''
+
+
+import sys
+import toscaparser.utils.yamlparser as yaml
+
+import docx
+from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
+
+PRINT_TRESHOLD = 1
+
+TEMPLATES = {}
+
+FNS = {
+    'VNFD' : 'etsi_nfv_sol001_vnfd_2_5_1_types.yaml',
+    'NSD'  : 'etsi_nfv_sol001_nsd_2_5_1_types.yaml',
+    'PNFD' : 'etsi_nfv_sol001_pnfd_2_5_1_types.yaml'
+}
+
+TOSCA_TYPES = [
+    'data_types',
+    'artifact_types',
+    'capability_types',
+    'requirements_types',
+    'relationship_types',
+    'interface_types',
+    'node_types',
+    'group_types',
+    'policy_types'
+]
+
+TOSCA_TYPES_PRETTYPRINT = {
+    'data_types': 'Data Types',
+    'artifact_types': 'Artifact Types',
+    'capability_types': 'Capability Types',
+    'requirements_types': 'Requirements types',
+    'relationship_types': 'Relationship Types',
+    'interface_types': 'Interface Types',
+    'node_types': 'Node Types',
+    'group_types': 'Group Types',
+    'policy_types': 'Policy Types'
+}
+
+
+IDS = [6, 2, 1, 1]
+
+def load_template(file_path, templs, key):
+    '''
+    Loads the content of the file at file_patch into the YAML templates array
+    '''
+    yaml_data = open(file_path).read()
+    #print("+++++++++++++++++++++++++++++++++++++")
+    #print(yaml_data)
+    #print("+++++++++++++++++++++++++++++++++++++")
+    templs[key] = yaml.simple_ordered_parse(yaml_data)
+
+def print_lvl(num, txt):
+    if num + 1 > PRINT_TRESHOLD:
+        return
+    index = ".".join(map(str, IDS[:(num+1)]))
+    print index +  " " + ('-'*(num+1)) + ' ' + txt
+
+def add_heading_with_num(num, txt, doc):
+    '''
+    Add a new heading to the document, with the calculated index number
+    '''
+    index = ".".join(map(str, IDS[:(num+1)]))
+    doc.add_heading(index + " " + txt, num)
+
+def cell_text_bold(cell):
+    cell.paragraphs[0].runs[0].font.bold = True
+
+def cell_text_centered(cell):
+    cell.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
+
+def mk_props_table_hdr(table):
+    hdr_cells = table.rows[0].cells
+    hdr_cells[0].text = 'Name'
+    hdr_cells[1].text = 'Required'
+    hdr_cells[2].text = 'Type'
+    hdr_cells[3].text = 'Constraints'
+    hdr_cells[4].text = 'Description'
+    map(cell_text_bold, hdr_cells)
+    map(cell_text_centered, hdr_cells)
+
+def dt_name_from_path(dt_path):
+    return dt_path.split('.')[-1]
+
+def prop_field_to_str(prop_field):
+    if type(prop_field) == bool:
+        return 'yes' if prop_field else 'no'
+    return str(prop_field)
+
+def add_prop_row(prop_name, prop_fields, table):
+    '''
+    Add a row to table and fills it with info from prop
+    '''
+    nrow = table.add_row()
+    prop_cells = nrow.cells
+    prop_cells[0].text = prop_name
+
+    all_fields = ['required', 'type', 'constraints', 'description']
+
+    counter = 1
+    for field in all_fields:
+        if field in prop_fields:
+            prop_cells[counter].text = prop_field_to_str(prop_fields[field])
+        counter = counter + 1
+
+def print_all_types(templ, lvl, doc):
+    for tosca_type in TOSCA_TYPES:
+        if not tosca_type in templ:
+            continue
+        print_lvl(lvl, tosca_type)
+        add_heading_with_num(lvl, TOSCA_TYPES_PRETTYPRINT[tosca_type], doc)
+        for data_type in templ[tosca_type]:
+            print_lvl(lvl + 1, data_type)
+            add_heading_with_num(lvl + 1, data_type, doc)
+
+            if 'description' in templ[tosca_type][data_type]:
+                print_lvl(lvl + 2, 'Description')
+                add_heading_with_num(lvl + 2, 'Description', doc)
+                doc.add_paragraph(templ[tosca_type][data_type]['description'])
+                IDS[lvl+2] = IDS[lvl+2] + 1
+
+            if 'properties' in templ[tosca_type][data_type]:
+                print_lvl(lvl + 2, 'Properties')
+                add_heading_with_num(lvl + 2, 'Properties', doc)
+                # num_row = templ[tosca_type][data_type]['properties'].items()
+                doc.add_paragraph("The properties of the "+
+                    dt_name_from_path(data_type)
+                    +" data type shall comply with the provisions set out in table REF_TBD.")
+                table = doc.add_table(rows=1, cols=5)
+                mk_props_table_hdr(table)
+                for prop in templ[tosca_type][data_type]['properties']:
+                    # print "PROP: " + prop + ", VAL: " + str(templ[tosca_type][data_type]['properties'][prop])
+                    add_prop_row(prop, templ[tosca_type][data_type]['properties'][prop], table)
+                IDS[lvl+2] = IDS[lvl+2] + 1
+
+            print_lvl(lvl + 2, 'Definition')
+            add_heading_with_num(lvl + 2, 'Definition', doc)
+            doc.add_paragraph("The syntax of the "+
+                dt_name_from_path(data_type)+
+                " data type shall comply with the following definition:")
+            def_table = doc.add_table(rows=1, cols=1)
+            def_table.rows[0].cells[0].text = 'TBD'
+            IDS[lvl+2] = IDS[lvl+2] + 1
+
+            print_lvl(lvl + 2, 'Examples')
+            add_heading_with_num(lvl + 2, 'Examples', doc)
+            def_table = doc.add_table(rows=1, cols=1)
+            def_table.rows[0].cells[0].text = 'TBD'
+            IDS[lvl+2] = IDS[lvl+2] + 1
+
+            print_lvl(lvl + 2, 'Additional Requirements')
+            add_heading_with_num(lvl + 2, 'Additional Requirements', doc)
+            doc.add_paragraph("None.")
+            IDS[lvl+2] = IDS[lvl+2] + 1
+
+            IDS[lvl+1] = IDS[lvl+1] + 1
+            IDS[lvl+2] = 1
+
+        IDS[lvl+1] = 1
+        IDS[lvl] = IDS[lvl] + 1
+    IDS[lvl] = 2
+
+def generate_from_file(fn, doc, fpath):
+    load_template(fpath, TEMPLATES, fn)
+    print_lvl(0, fn)
+    add_heading_with_num(0, fn, doc)
+    print_all_types(TEMPLATES[fn], 1, doc)
+    #print TEMPLATES[fn]
+
+if __name__ == "__main__":
+    doc = docx.Document()
+
+    if len(sys.argv) < 2:
+        print "Usage: robot2doc <robot_file_or_dir> [<out_file> [spec_section_title]]"
+        sys.exit()
+
+    FOLDR = sys.argv[1]
+
+    print "Using folder: " + sys.argv[1]
+
+    for fn in ['VNFD', 'NSD', 'PNFD']:
+        generate_from_file(fn, doc, FOLDR + '/' + FNS[fn])
+        IDS[0] = IDS[0] + 1
+
+    doc.save('sol001.docx')
diff --git a/web_app.py b/web_app.py
new file mode 100644
index 0000000..203790b
--- /dev/null
+++ b/web_app.py
@@ -0,0 +1,94 @@
+#!/bin/bash
+
+import os
+
+from flask import Flask, flash, request, redirect, url_for, send_file
+from werkzeug.utils import secure_filename
+import docx
+
+import tosca2doc
+
+app = Flask(__name__)
+
+UPLOAD_FOLDER = '/tmp/upload'
+
+ALLOWED_EXTENSIONS = set(['txt', 'yaml', 'docx'])
+
+app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
+app.secret_key = 'super secret key'
+app.config['SESSION_TYPE'] = 'filesystem'
+
+HOME='''
+<!doctype html>
+<title>tosca2doc</title>
+<h1>tosca2doc & doc2tosca</h1>
+<h2>tosca2doc</h2>
+<form action="/tosca2doc" method="post" enctype="multipart/form-data">
+Tosca YAML file:
+<input type="file" name="file" multiple=""/>
+<input type="submit" value="Upload" />
+</form>
+<h2>doc2tosca</h2>
+'''
+
+TOSCA_DEFS=['VNFD', 'NSD', 'PNFD']
+
+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
+
+
+@app.route("/")
+def hello():
+    return HOME 
+
+@app.route("/tosca2doc", methods=['POST'])
+def mk_tosca2doc():
+
+    if 'file' not in request.files:
+        flash('No file part')
+        return redirect(request.url)
+
+    ufiles=request.files.getlist("file")
+
+    for tosca_def in TOSCA_DEFS:
+        found=False
+        for uploaded_file in ufiles:
+            if tosca_def in uploaded_file.filename or \
+                tosca_def.lower() in uploaded_file.filename:
+                found=True
+                #if uploaded_file:
+                #    print "-------------------"
+                #    print uploaded_file.read()
+                #    print "-------------------"
+        if not found:
+            flash('No file part')
+            print('No file part')
+            return redirect("/")
+
+    for file in ufiles:
+        if file.filename == '':
+            print('No selected file')
+            flash('No selected file')
+            return redirect("/")
+
+    doc = docx.Document()    
+
+    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)
+
+    doc.save('/tmp/myfile.docx')
+    return send_file('/tmp/myfile.docx')
+
+    return ("No content found")
\ No newline at end of file
-- 
GitLab