--- a/.hgignore Tue Oct 14 18:00:13 2014 +0200
+++ b/.hgignore Tue Oct 14 05:07:37 2014 +0200
@@ -1,6 +1,7 @@
syntax: regexp
-^utils/pianoroll_test.*
+^utils/pianoroll_test
+^utils/pianoroll_sample_
^client/bower_components$
^client/build$
^client/node_modules$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/__init__.py Tue Oct 14 05:07:37 2014 +0200
@@ -0,0 +1,4 @@
+#
+# See LICENCE for detail
+# Copyright (c) 2014 IRI
+#
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/database.py Tue Oct 14 05:07:37 2014 +0200
@@ -0,0 +1,54 @@
+#
+# See LICENCE for detail
+# Copyright (c) 2014 IRI
+#
+
+from sqlalchemy import create_engine, MetaData
+from sqlalchemy.orm import scoped_session, sessionmaker
+from sqlalchemy.ext.declarative import declarative_base
+
+import psycopg2.extras
+
+from twisted.python import log
+
+from txpostgres.txpostgres import Connection, ConnectionPool
+
+import config
+
+
+engine = create_engine(config.CONN_STR, convert_unicode=True)
+db_session = scoped_session(sessionmaker(autocommit=False,
+ autoflush=False,
+ bind=engine))
+
+Base = declarative_base()
+Base.query = db_session.query_property()
+
+def init_db():
+ # import all modules here that might define models so that
+ # they will be registered properly on the metadata. Otherwise
+ # you will have to import them first before calling init_db()
+ import models
+ Base.metadata.create_all(bind=engine)
+
+
+class DictConnection(Connection):
+
+ @staticmethod
+ def connectionFactory(*args, **kwargs):
+ kwargs['connection_factory'] = psycopg2.extras.DictConnection
+ return psycopg2.connect(*args, **kwargs)
+
+
+class DictConnectionPool(ConnectionPool):
+ connectionFactory = DictConnection
+
+
+def create_connection_pool(conn_string):
+
+ created_connection_pool = DictConnectionPool(None, conn_string)
+
+ d = created_connection_pool.start()
+ d.addErrback(log.err)
+
+ return created_connection_pool, d
--- a/annot-server/models.py Tue Oct 14 18:00:13 2014 +0200
+++ b/annot-server/models.py Tue Oct 14 05:07:37 2014 +0200
@@ -8,17 +8,39 @@
import json
import uuid
-def get_table_create_stmt():
- return (
- "CREATE TABLE IF NOT EXISTS annotations ( "
- "id serial PRIMARY KEY, "
- "uuid uuid UNIQUE, "
- "created timestamp default (now() at time zone 'utc') NOT NULL, "
- "ts timestamptz NOT NULL, "
- "event varchar(255) NOT NULL, "
- "channel varchar(255) NOT NULL, "
- "content json);"
- )
+from sqlalchemy import Column, Integer, String, DateTime, Table, Index, text
+from sqlalchemy.sql import func
+from sqlalchemy.dialects.postgresql import UUID, JSON
+
+from database import Base, engine
+
+#def get_table_create_stmt():
+# return (
+# "CREATE TABLE IF NOT EXISTS annotations ( "
+# "id serial PRIMARY KEY, "
+# "uuid uuid UNIQUE, "
+# "created timestamp default (now() at time zone 'utc') NOT NULL, "
+# "ts timestamptz NOT NULL, "
+# "event varchar(255) NOT NULL, "
+# "channel varchar(255) NOT NULL, "
+# "content json);"
+# )
+
+class Annotation(Base):
+ __tablename__ = 'annotations'
+
+ id = Column(Integer, primary_key=True, nullable=False)
+ uuid = Column(UUID, unique=True, nullable=False)
+ created = Column(DateTime, nullable=False, server_default=text("(now() at time zone 'utc')") )
+ ts = Column(DateTime(timezone=True), nullable=False)
+ event = Column(String(255), nullable=False)
+ channel = Column(String(255), nullable=False)
+ content = Column(JSON)
+
+Index('idx_event', Annotation.event)
+Index('idx_channel', Annotation.channel)
+Index('idx_ts', Annotation.ts)
+
def insert_annot_async(params, conn):
@@ -31,7 +53,9 @@
if 'ts' not in params:
params['ts'] = datetime.utcnow()
- defer = conn.runOperation("INSERT INTO annotations (uuid, ts, event, channel, content) VALUES (%(uuid)s, %(ts)s, %(event)s, %(channel)s, %(content)s)", params)
- defer.addCallback(lambda _: params)
+ stmt = Annotation.__table__.insert().values(**params).compile(engine)
+
+ defer = conn.runOperation(stmt.string, stmt.params)
+ defer.addCallback(lambda _: stmt.params)
return defer
--- a/annot-server/server.tac Tue Oct 14 18:00:13 2014 +0200
+++ b/annot-server/server.tac Tue Oct 14 05:07:37 2014 +0200
@@ -10,21 +10,22 @@
import psycopg2.extras
from twisted.application import service
+from twisted.internet import reactor
from twisted.python import log
from txpostgres import txpostgres
from annotserver import make_service
import config
-from models import get_table_create_stmt
-from utils import create_connection_pool
+from database import create_connection_pool, init_db, db_session
psycopg2.extras.register_uuid()
+init_db()
conn, d = create_connection_pool(config.CONN_STR)
#to do treat error
-d.addCallback(lambda _: conn.runOperation(get_table_create_stmt()))
+#d.addCallback(lambda _: conn.runOperation(get_table_create_stmt()))
#TOODO Log
#log.startLogging(sys.stdout)
@@ -34,3 +35,5 @@
annotserver = make_service(conn)
annotserver.setServiceParent(service.IServiceCollection(application))
+
+reactor.addSystemEventTrigger('before', 'shutdown', lambda: db_session.remove())
--- a/annot-server/templates/annot.html Tue Oct 14 18:00:13 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <link rel="icon" href="data:;base64,=">
- <script type="text/javascript">
- var sock = null;
- var ellog = null;
-
- window.onload = function() {
-
- ellog = document.getElementById('log');
-
- var wsuri;
- if (window.location.protocol === "file:") {
- wsuri = "ws://127.0.0.1:8090/annot";
- } else {
- wsuri = "ws://" + window.location.hostname + ":8090/annot";
- }
- wsuri = wsuri + "?event=test"
-
- if ("WebSocket" in window) {
- sock = new WebSocket(wsuri);
- } else if ("MozWebSocket" in window) {
- sock = new MozWebSocket(wsuri);
- } else {
- log("Browser does not support WebSocket!");
- window.location = "http://autobahn.ws/unsupportedbrowser";
- }
-
- if (sock) {
- sock.onopen = function() {
- log("Connected to " + wsuri);
- }
-
- sock.onclose = function(e) {
- log("Connection closed (wasClean = " + e.wasClean + ", code = " + e.code + ", reason = '" + e.reason + "')");
- sock = null;
- }
-
- sock.onmessage = function(e) {
- log("Got message: " + e.data);
- }
- }
- };
-
- function send() {
- var msg = document.getElementById('message').value;
- if (sock) {
- new_annot = {
- categories : [msg],
- user : "admin"
- }
- sock.send(JSON.stringify(new_annot));
- log("Sent: " + JSON.stringify(new_annot));
- } else {
- log("Not connected.");
- }
- };
-
- function log(m) {
- ellog.innerHTML += m + '\n';
- ellog.scrollTop = ellog.scrollHeight;
- };
- </script>
- </head>
- <body>
- <h1>OSC websocket Test</h1>
- <noscript>You must enable JavaScript</noscript>
- <form>
- <p>Message: <input id="message" type="text" size="50" maxlength="50" value="Hello, world!"></p>
- </form>
- <button onclick='send();'>Send Message</button>
- <pre id="log" style="height: 20em; overflow-y: scroll; background-color: #faa;"></pre>
- </body>
-</html>
--- a/annot-server/templates/index.html Tue Oct 14 18:00:13 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <link rel="icon" href="data:;base64,=">
- <script type="text/javascript">
- var sock = null;
- var ellog = null;
-
- window.onload = function() {
-
- ellog = document.getElementById('log');
-
- var wsuri;
- if (window.location.protocol === "file:") {
- wsuri = "ws://127.0.0.1:8090/broadcast";
- } else {
- wsuri = "ws://" + window.location.hostname + ":8090/broadcast";
- }
- if ("WebSocket" in window) {
- sock = new WebSocket(wsuri);
- } else if ("MozWebSocket" in window) {
- sock = new MozWebSocket(wsuri);
- } else {
- log("Browser does not support WebSocket!");
- window.location = "http://autobahn.ws/unsupportedbrowser";
- }
-
- if (sock) {
- sock.onopen = function() {
- log("Connected to " + wsuri);
- }
-
- sock.onclose = function(e) {
- log("Connection closed (wasClean = " + e.wasClean + ", code = " + e.code + ", reason = '" + e.reason + "')");
- sock = null;
- }
-
- sock.onmessage = function(e) {
- log("Got message: " + e.data);
- }
- }
- };
-
- function log(m) {
- ellog.innerHTML += m + '\n';
- ellog.scrollTop = ellog.scrollHeight;
- };
- </script>
- <link rel="stylesheet" type="text/css" href="/static/css/base.css">
- </head>
- <body>
- <h1>OSC websocket Test</h1>
- <noscript>You must enable JavaScript</noscript>
- <pre id="log"></pre>
- </body>
-</html>
--- a/annot-server/utils.py Tue Oct 14 18:00:13 2014 +0200
+++ b/annot-server/utils.py Tue Oct 14 05:07:37 2014 +0200
@@ -4,33 +4,6 @@
# Copyright (c) 2014 IRI
#
-import psycopg2.extras
-
-from twisted.python import log
-
-from txpostgres.txpostgres import Connection, ConnectionPool
-
PIANOROLL_CHANNEL = 'PIANOROLL'
ANNOTATION_CHANNEL = 'ANNOT'
-
-class DictConnection(Connection):
-
- @staticmethod
- def connectionFactory(*args, **kwargs):
- kwargs['connection_factory'] = psycopg2.extras.DictConnection
- return psycopg2.connect(*args, **kwargs)
-
-
-class DictConnectionPool(ConnectionPool):
- connectionFactory = DictConnection
-
-
-def create_connection_pool(conn_string):
-
- created_connection_pool = DictConnectionPool(None, conn_string)
-
- d = created_connection_pool.start()
- d.addErrback(log.err)
-
- return created_connection_pool, d
--- a/annot-server/webapp.py Tue Oct 14 18:00:13 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-
-#
-# See LICENCE for detail
-# Copyright (c) 2014 IRI
-#
-
-import uuid
-
-from flask import Flask, render_template
-
-import config
-
-app = Flask(__name__)
-app.secret_key = str(uuid.uuid4())
-app.config.from_object(config)
-
-@app.route('/')
-def page_home():
- return render_template('index.html')
- #return render_template('annotationclient.html', logging=True)
-
-
-@app.route('/annot')
-def page_annot():
- return render_template('annot.html')
-
-
-@app.route('/annotationclient')
-def page_annotationclient():
- return render_template('annotationclient.html', logging=True)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/webapp/__init__.py Tue Oct 14 05:07:37 2014 +0200
@@ -0,0 +1,23 @@
+#
+# See LICENCE for detail
+# Copyright (c) 2014 IRI
+#
+
+import uuid
+import json
+
+from flask import Flask
+
+import config
+import database
+
+app = Flask(__name__)
+app.secret_key = str(uuid.uuid4())
+app.debug = config.DEBUG
+app.config.from_object(config)
+
+import webapp.views
+
+@app.teardown_appcontext
+def shutdown_session(exception=None):
+ database.db_session.remove()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/webapp/templates/annot.html Tue Oct 14 05:07:37 2014 +0200
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="icon" href="data:;base64,=">
+ <script type="text/javascript">
+ var sock = null;
+ var ellog = null;
+
+ window.onload = function() {
+
+ ellog = document.getElementById('log');
+
+ var wsuri;
+ if (window.location.protocol === "file:") {
+ wsuri = "ws://127.0.0.1:8090/annot";
+ } else {
+ wsuri = "ws://" + window.location.hostname + ":8090/annot";
+ }
+ wsuri = wsuri + "?event=test"
+
+ if ("WebSocket" in window) {
+ sock = new WebSocket(wsuri);
+ } else if ("MozWebSocket" in window) {
+ sock = new MozWebSocket(wsuri);
+ } else {
+ log("Browser does not support WebSocket!");
+ window.location = "http://autobahn.ws/unsupportedbrowser";
+ }
+
+ if (sock) {
+ sock.onopen = function() {
+ log("Connected to " + wsuri);
+ }
+
+ sock.onclose = function(e) {
+ log("Connection closed (wasClean = " + e.wasClean + ", code = " + e.code + ", reason = '" + e.reason + "')");
+ sock = null;
+ }
+
+ sock.onmessage = function(e) {
+ log("Got message: " + e.data);
+ }
+ }
+ };
+
+ function send() {
+ var msg = document.getElementById('message').value;
+ if (sock) {
+ new_annot = {
+ categories : [msg],
+ user : "admin"
+ }
+ sock.send(JSON.stringify(new_annot));
+ log("Sent: " + JSON.stringify(new_annot));
+ } else {
+ log("Not connected.");
+ }
+ };
+
+ function log(m) {
+ ellog.innerHTML += m + '\n';
+ ellog.scrollTop = ellog.scrollHeight;
+ };
+ </script>
+ </head>
+ <body>
+ <h1>OSC websocket Test</h1>
+ <noscript>You must enable JavaScript</noscript>
+ <form>
+ <p>Message: <input id="message" type="text" size="50" maxlength="50" value="Hello, world!"></p>
+ </form>
+ <button onclick='send();'>Send Message</button>
+ <pre id="log" style="height: 20em; overflow-y: scroll; background-color: #faa;"></pre>
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/webapp/templates/annotationclient.html Tue Oct 14 05:07:37 2014 +0200
@@ -0,0 +1,102 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>Mons by IRI</title>
+ <link rel="stylesheet" href="{{ config['STATIC_URL'] }}/css/lib.css">
+ <link rel="stylesheet" href="{{ config['STATIC_URL'] }}/css/app.css">
+</head>
+<body ng-controller="homeCtrl" ng-app="mons" ng-cloak>
+ <div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <form role="form">
+ <input class="form-control" placeholder="Nom d'utilisateur" ng-model="username"/>
+ </form>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12">
+ <form role="form">
+ <autocomplete ng-model="yourchoice" data="allCatLabels" attr-input-class="form-control" attr-placeholder="Catégories..." ></autocomplete>
+ </form>
+ </div>
+ </div>
+ <div class="row mons-content">
+ <div class="mons-button hand return" ng-style="returnVisStyle" ng-click="selectLevel()" ng-init="returnVisStyle={visibility:'hidden'}">
+ <div class="content">
+ <div class="table">
+ <div class="table-cell">
+ <p class="large-cat">RETOUR</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="mons-button hand send" id="sendButton" ng-click="sendAnnotation(yourchoice)" ng-class="{'success-border':sendBtnSuccess}">
+ <div class="content">
+ <div class="table">
+ <div class="table-cell">
+ <p class="large-cat">ENVOYER</p>
+ <p class="normal-cat">la catégorie saisie</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="mons-content">
+ <div ng-show="!selectedlevel">
+ <div class="mons-button hand" ng-repeat="c in data.categories" style="background-color: {{ '{{' }} c.color {{ '}}' }}"
+ ng-click="selectLevel(c.label, c.code, c)" ng-class="{'success-border':c.sendSuccess}">
+ <div class="content">
+ <div class="table">
+ <div class="table-cell">
+ <p class="large-cat">{{ '{{' }} c.label {{ '}}' }}</p>
+ <p class="normal-cat">{{ '{{' }} c.full_label {{ '}}' }}</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div ng-show="selectedlevel">
+ <div class="mons-button hand" ng-repeat="c in selectedlevel" style="background-color: {{ '{{' }} c.color {{ '}}' }}"
+ ng-click="sendAnnotation(c.label, c.code, c)" ng-class="{'success-border':c.sendSuccess}">
+ <div class="content">
+ <div class="table">
+ <div class="table-cell">
+ <p class="large-cat">{{ '{{' }} c.label {{ '}}' }}</p>
+ <p class="normal-cat">{{ '{{' }} c.full_label {{ '}}' }}</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <footer>
+ {% if logging %}<div class="row">
+ <pre id="log" style="height: 20em; overflow-y: scroll; background-color: #faa; text-align: left;"></pre>
+ </div>{% endif %}
+ <div class="row">
+ <div class="col-md-12 text-center">
+ mons vBeta - ©IRI-2014
+ </div>
+ </div>
+ </footer>
+ <div class="row messages">
+ <div class="alert" ng-class="{'alert-success':showSuccessAlert, 'alert-danger':!showSuccessAlert}" role="alert" ng-show="showAlertDiv">{{ '{{' }} alertMessage {{ '}}' }}</div>
+ </div>
+ </div>
+ <script type="text/javascript" src="{{ config['STATIC_URL'] }}/js/lib.js"></script>
+ <!--script type="text/javascript" src="{{ pre_static_path }}static/js/templates.js"></script-->
+ <script type="text/javascript" src="{{ config['STATIC_URL'] }}/js/app.js"></script>
+ <script type="text/javascript">
+ angular.module("mons")
+ .value('context', {
+ {% if logging %}logging: true,{% endif %}
+ urls: {
+ dataUrl: "{{ config['STATIC_URL'] }}/data/categories.json"
+ }
+ });
+ </script>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/webapp/templates/index.html Tue Oct 14 05:07:37 2014 +0200
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="icon" href="data:;base64,=">
+ <script type="text/javascript">
+ var sock = null;
+ var ellog = null;
+
+ window.onload = function() {
+
+ ellog = document.getElementById('log');
+
+ var wsuri;
+ if (window.location.protocol === "file:") {
+ wsuri = "ws://127.0.0.1:8090/broadcast";
+ } else {
+ wsuri = "ws://" + window.location.hostname + ":8090/broadcast";
+ }
+ if ("WebSocket" in window) {
+ sock = new WebSocket(wsuri);
+ } else if ("MozWebSocket" in window) {
+ sock = new MozWebSocket(wsuri);
+ } else {
+ log("Browser does not support WebSocket!");
+ window.location = "http://autobahn.ws/unsupportedbrowser";
+ }
+
+ if (sock) {
+ sock.onopen = function() {
+ log("Connected to " + wsuri);
+ }
+
+ sock.onclose = function(e) {
+ log("Connection closed (wasClean = " + e.wasClean + ", code = " + e.code + ", reason = '" + e.reason + "')");
+ sock = null;
+ }
+
+ sock.onmessage = function(e) {
+ log("Got message: " + e.data);
+ }
+ }
+ };
+
+ function log(m) {
+ ellog.innerHTML += m + '\n';
+ ellog.scrollTop = ellog.scrollHeight;
+ };
+ </script>
+ <link rel="stylesheet" type="text/css" href="/static/css/base.css">
+ </head>
+ <body>
+ <h1>OSC websocket Test</h1>
+ <noscript>You must enable JavaScript</noscript>
+ <pre id="log"></pre>
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/webapp/views.py Tue Oct 14 05:07:37 2014 +0200
@@ -0,0 +1,28 @@
+#
+# See LICENCE for detail
+# Copyright (c) 2014 IRI
+#
+
+from flask import render_template, jsonify, request
+
+from webapp import app
+
+@app.route('/')
+def page_home():
+ return render_template('index.html')
+ #return render_template('annotationclient.html', logging=True)
+
+
+@app.route('/annot')
+def page_annot():
+ return render_template('annot.html')
+
+
+@app.route('/annotationclient')
+def page_annotationclient():
+ return render_template('annotationclient.html', logging=True)
+
+
+@app.route('/api/test', methods=['PUT', 'POST'])
+def new():
+ return jsonify(request.get_json(force=False))
--- a/client/gulpfile.js Tue Oct 14 18:00:13 2014 +0200
+++ b/client/gulpfile.js Tue Oct 14 05:07:37 2014 +0200
@@ -3,8 +3,8 @@
var gutil = require('gulp-util')
var plugins = require("gulp-load-plugins")({lazy:false});
-var templateFolder = '../annot-server/templates/';
-var templateFileDest = '../annot-server/templates/annotationclient.html';
+var templateFolder = '../annot-server/webapp/templates/';
+var templateFileDest = '../annot-server/webapp/templates/annotationclient.html';
var staticFolder = '../annot-server/static';
var clientBaseName = 'app';
--- a/requirements.txt Tue Oct 14 18:00:13 2014 +0200
+++ b/requirements.txt Tue Oct 14 05:07:37 2014 +0200
@@ -1,8 +1,17 @@
Flask==0.10.1
+Flask-SQLAlchemy==2.0
+Jinja2==2.7.3
+MarkupSafe==0.23
+SQLAlchemy==0.9.8
Twisted==14.0.2
+Werkzeug==0.9.6
autobahn==0.9.1
+itsdangerous==0.24
+midi==v0.2.3
ntplib==0.3.2
psycopg2==2.5.4
-#c.f. https://confluence.atlassian.com/display/BBKB/abort%3A+certificate+for+bitbucket.org+has+unexpected+fingerprint
--e hg+https://bitbucket.org/IRI/txosc/get/tip.tar.gz#egg=txosc
+six==1.8.0
+txosc==0.2.0
txpostgres==1.2.0
+wsgiref==0.1.2
+zope.interface==4.1.1