-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
12,495 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Oops, something went wrong.