Skip to content

Commit

Permalink
prepare for 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
guillain committed Mar 28, 2017
1 parent b864a4d commit 0acf0bb
Show file tree
Hide file tree
Showing 34 changed files with 12,495 additions and 1 deletion.
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,43 @@
# TechRequest
Web interface to drive Cisco Spark for Technical Request
Web integration of Cisco Spark to provide continuous engagement system.

## Why I've done that?
That's the capability for the external people to request (open folder) and exchange with an enterprise via web form and follow its folder.
During that the enterprise continue to work on the folder with Spark and all associated communication features.

## Scenario
The scenario can be describe like that :
* AirLines open a folder via a web form
* Automatically: the Spark room (Space) is created, the AirLine, Field Representative and Expert are associated to this Space.
* The Expert works on the folder with the Field Representative support and communicate through the file sharing, webex and video conferencing, white board and chat provided by the Space.
* At the end of the folder process, only the admin can close the folder and the dump of the Space stay available via the Web form.

## Requirements
Account
* Cisco Spark (for free)

Servers
* Python 2.7
** flask
** werkzeug
** MySQLdb
* MySQL

Two web server configurations available
* Apache and WSGI
* python CLI (should be considered as dev pf even if tips for exposure is provided)

### Local database
* Manage user independantly of Spark Cloud user registration system. This is to solve an access issue for external people who doesn't use Spak.
* Manage users, groups and admin rights (via web forms)
* Log each events and Spark messages and provide permnanent access to the dump and real time replication features (useful for third party integration)
* Also useful if we consider that the log function can be adapted for noSQL and data analytics systems

## HowTo
* [Setup](doc/setup.md)
* [Configuration](doc/configuration.md)

## ToDo list
* [ToDo](doc/todo.md)


17 changes: 17 additions & 0 deletions TechRequest.wsgi
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/python
# Target: apache swgi mapping
# Version: 0.1
# Date: 2017/01/04
# Mail: [email protected]
# Copyright 2017 GPL - Guillain

import os
import sys
import logging

sys.path.insert(0, '/var/www/TechRequest')
os.environ['FLASK_SETTING'] = '/var/www/TechRequest/conf/settings.cfg'

logging.basicConfig(stream=sys.stderr)

from TechRequest import app as application
129 changes: 129 additions & 0 deletions TechRequest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Target: app init
# Version: 0.1
# Date: 2017/01/04
# Mail: [email protected]
# Copyright 2017 GPL - Guillain

from flask import Flask, session, redirect, url_for, escape, request
from flask import render_template, jsonify, flash, send_from_directory
from werkzeug.utils import secure_filename
from static.py.tools import logger, exeReq, wEvent
import re, os, sys, urllib

sys.path.append(os.path.dirname(__file__))

# Conf and create app
app = Flask(__name__)
app.config.from_object(__name__)
app.config.from_envvar('FLASK_SETTING')

# Import TechRequest features
from static.py.TechRequest import techreq_api
app.register_blueprint(techreq_api)

# WEB mgt ----------------------------------------
@app.route('/')
def my_form():
if 'login' in session:
return render_template('new.html')
return render_template("login.html")

# Login --------------------------------------------
@app.route('/login', methods=['POST'])
def login():
error = None
if 'login' in session:
return render_template('new.html')

login = request.form['login']
if not login:
wEvent('login','','Thanks to provide login','KO')
return render_template('login.html')

password = request.form['password']
if not password:
wEvent('login','','Thanks to provide password','KO')
return render_template('login.html')

try:
data = exeReq("SELECT uid, grp, email, mobile, admin FROM users WHERE login='"+login+"' AND pw_hash=PASSWORD('"+password+"')")
except Exception as e:
wEvent('login','','DB connection/request error', 'KO')
return render_template('login.html')

try:
if data is None or data[0][0] is None:
wEvent('login','','Wrong email or password','KO')
return render_template('login.html')
except Exception as e:
wEvent('login','','Wrong email or password','KO')
return render_template('login.html')

try:
session['login'] = str(login)
session['uid'] = str(data[0][0])
session['grp'] = str(data[0][1])
session['email'] = str(data[0][2])
session['mobile'] = str(data[0][3])
session['admin'] = str(data[0][4])
wEvent('login',session['uid'],"User "+session['login']+" logged",'OK')
return render_template('new.html')
except Exception as e:
wEvent('login','','Wrong email or password','KO')
return render_template('login.html')

# Logout --------------------------------------------------
@app.route('/logout')
def logout():
wEvent('logout',session['uid'],'You were logged out','OK')
session.clear()
return redirect('/')

# Server file ---------------------------------------------
@app.route('/uploads/<path:path>')
def send_uploads(path):
return send_from_directory('uploads', path)

@app.route('/downloads/<path:path>')
def send_downloads(path):
return send_from_directory('downloads', path)

# Upload file ---------------------------------------------
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']

@app.route('/upload_file', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
session.pop('filename', None)

# check if the post request has the file part
if 'file' not in request.files:
wEvent('upload_file',session['uid'],'No file part','KO')
return render_template('upload_file.html', error = 'No file part')
file = request.files['file']
if file.filename == '':
wEvent('upload_file',session['uid'],'No file part','KO')
return render_template('upload_file.html', error = 'No file part')
if file and allowed_file(file.filename):
session['filename'] = str(secure_filename(file.filename))
file.save(os.path.join(app.config['UPLOAD_FOLDER'], session['filename']))
wEvent('upload_file',session['uid'],'File Uploaded, filename: '+session['filename'],'OK')
return redirect(url_for('uploaded_file', filename=session['filename']))
else:
wEvent('upload_file',session['uid'],'File is not allowed','KO')
return render_template('upload_file.html', error = 'File is not allowed')
return render_template('upload_file.html')

@app.route('/uploaded_file', methods=['GET', 'POST'])
def uploaded_file():
wEvent('uploaded_file',session['uid'],'File uploaded for space id','OK')
return render_template('update.html')


# End of App --------------------------------------------------------------------------
if __name__ == '__main__':
sess.init_app(app)
app.debug = True
app.run()
Empty file added TechRequest/static/__init__.py
Empty file.
180 changes: 180 additions & 0 deletions TechRequest/static/css/TechRequest.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
Target: TechRequest style and actions...
Version: 0.1
Date: 2017/01/04
Mail: [email protected]
Copyright 2017 GPL - Guillain
*/

/* --- display additionnal info when onmouse --- */
.hideme {
display:none;
background-color:rgb(157,255,255);
padding:5px;
}

/* popup background */
.popup {
text-align: center;
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba( 255, 255, 255, .8 )
url('')
50% 50%
no-repeat;
}

/* Loading background */
.modal {
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba( 255, 255, 255, .8 )
url('/static/image/loading.gif')
50% 50%
no-repeat;
}
body.loading {
overflow: hidden;
}
body.loading .modal {
display: block;
}

/* --- Decoration --- */
body {
margin: 0;
background: #ffffff;
/* font-family: arial, sans-serif; */
font-family: Helvetica Neue,Arial;
font-size: 10; /*rem;*/
font-weight: 200;
}
header {
background: #f7f7f7;
}
header,airlines,fieldrep,expert,users,user,new,update,view,dashboard,footer {
margin: .2em; /* .4 */
padding: 1em; /* 1 */
border-radius: 6px; /* 6 */
}
airlines,fieldrep,expert,update,users,user,new,view {
width: 33%;
text-align: center;
overflow-y:auto;
overflow-x:hidden;
}
dashboard {
width: 66%;
text-align: center;
overflow-y:auto;
overflow-x:hidden;
}

footer {
background: #f7f7f7; /* #eff8f6;*/
}

ul {
list-style-type: square;
display: block;
text-align: left;
}
table.tblCenter {
width:100%;
text-align: center;
table-layout: fixed;
}
td, th, td.tblLeft {
width:(100/x)%;
text-align: left;
}
td.tblCenter {
width:(100/x)%;
text-align: center;
}
td.tblRight {
width:(100/x)%;
text-align: right;
}
div {
border-radius: 6px;
text-align: center;
vertical-align: top;
}
input, select, textarea {
width : 150px;
}
select, textarea, input, button {
text-align: center;
display: inline-block;
font-family: serif;
border-radius: 6px;
}
.result,.title {
text-align: left;
}
.module {
text-align: center;
}
.iconimg {
width: 16px;
height: 16px;
border: 0;
}
.article {
float: left;
margin: 10px;
padding: 10px;
max-width: 300px;
height: 300px;
border: 0; /* 1px solid black; */
}
/*#botMsgDiv {
display: inline-block;
vertical-align: top;
}*/

/* --- Flexible placement --- */
* {
box-sizing: border-box; /* pour maîtriser width et flex-basis */
}
html {
display: flex;
flex-direction: column; /* correction bug IE de min-height non appliqué à body */
}
body {
display: flex;
flex-direction: column;
min-height: 10vh; /* toute la hauteur du viewport */
padding: .4em;
}
.wrapper {
flex: 1 1 auto;
display: flex;
overflow-y:auto;
overflow-x:hidden;
}
@media (max-width: 640px) {
.wrapper {
display: flex;
flex-direction: column;
}
dashboard {
order : 1;
width: auto;
}
airlines,fieldrep,expert,new,users,user,update,view,dashboard {
width: auto;
}
}

5 changes: 5 additions & 0 deletions TechRequest/static/css/bootstrap.min.css

Large diffs are not rendered by default.

Binary file added TechRequest/static/image/loading.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added TechRequest/static/image/spark.ico
Binary file not shown.
Loading

0 comments on commit 0acf0bb

Please sign in to comment.