end of admin. change the index page and add a redirect to it on the landing page
--- a/annot-server/annotserver.py Sun Oct 19 12:52:38 2014 +0200
+++ b/annot-server/annotserver.py Mon Oct 20 01:31:33 2014 +0200
@@ -7,8 +7,7 @@
from twisted.application import service, internet, strports
from twisted.internet import reactor
from twisted.python.threadpool import ThreadPool
-from twisted.web import server
-from twisted.web import resource
+from twisted.web import server, resource
from twisted.web.wsgi import WSGIResource
from twisted.web.static import Data, File
@@ -22,6 +21,12 @@
WS_PORT = 8090
OSC_PORT = 9090
+class BaseRedirect(resource.Resource):
+ isLeaf = True
+ def render_GET(self, request):
+ request.redirect(request.URLPath().child('p/'))
+ return ""
+
def make_service(conn, debug=False):
s = service.MultiService()
@@ -54,8 +59,8 @@
rootWs.putChild("broadcast", wsResource)
rootWs.putChild("annot", wsAnnotResource)
-
webResource = resource.Resource()
+ webResource.putChild("",BaseRedirect())
webResource.putChild(getattr(config,'STATIC_URL').lstrip('/'), File(getattr(config,'STATIC_ROOT')))
# Create the WSGI resource
wsgiAppAsResource = WSGIResource(reactor, wsgiThreadPool, app)
--- a/annot-server/models.py Sun Oct 19 12:52:38 2014 +0200
+++ b/annot-server/models.py Mon Oct 20 01:31:33 2014 +0200
@@ -8,7 +8,8 @@
import json
import uuid
-from sqlalchemy import Column, Integer, String, DateTime, Text, Table, Index, text, ForeignKey
+from sqlalchemy import (Column, Integer, String, DateTime, Text, Table, Index,
+ text, ForeignKey, Boolean)
from sqlalchemy.orm import relationship, backref
from sqlalchemy.sql import func
from sqlalchemy.dialects.postgresql import UUID, JSON
@@ -58,6 +59,8 @@
code = Column(String(255), unique=True, nullable=False)
label = Column(String(2048), nullable=False)
description = Column(Text(), nullable=True)
+ start_date = Column(DateTime(), nullable=True)
+ active = Column(Boolean(), nullable=False, default=True, server_default='1')
sessions = relationship("EventSession", order_by="EventSession.order", backref="event")
@@ -65,6 +68,8 @@
return self.code
Index('idx_event_code', Event.code)
+Index('idx_event_active', Event.active)
+Index('idx_event_start_date', Event.start_date)
class EventSession(Base):
__tablename__ = 'event_session'
@@ -73,7 +78,10 @@
event_id = Column(Integer, ForeignKey(Event.id), nullable=False)
project_id = Column(String(2048), nullable=True)
order = Column(Integer, nullable=False, default=0)
+ start_ts = Column(DateTime(timezone=True), nullable=True)
+ duration = Column(Integer, nullable=True)
categories_json = Column(JSON, nullable=True)
Index('idx_event_session_order', EventSession.order)
+Index('idx_event_session_start_ts', EventSession.start_ts)
--- a/annot-server/static/css/base.css Sun Oct 19 12:52:38 2014 +0200
+++ b/annot-server/static/css/base.css Mon Oct 20 01:31:33 2014 +0200
@@ -3,3 +3,11 @@
overflow-y: scroll;
background-color: #faa;
}
+
+div {
+ text-align:left;
+}
+
+.event-label {
+ font-size: 2em;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/webapp/admin.py Mon Oct 20 01:31:33 2014 +0200
@@ -0,0 +1,102 @@
+#
+# See LICENCE for detail
+# Copyright (c) 2014 IRI
+#
+
+import json
+import urllib
+
+from flask.ext.admin import Admin
+from flask.ext.admin.contrib.sqla import ModelView
+from flask.ext.admin.contrib.sqla.form import AdminModelConverter
+from flask.ext.admin.contrib.sqla.filters import BooleanEqualFilter
+from flask.ext.admin.model.form import InlineFormAdmin, converts
+
+from jinja2 import Markup
+
+from wtforms import fields
+
+import database
+import models
+import config
+from webapp import app
+
+admin = Admin(app)
+
+
+def build_ldt_url(view, context, model, name):
+ # `view` is current administrative view
+ # `context` is instance of jinja2.runtime.Context
+ # `model` is model instance
+ # `name` is property name
+ if not model.project_id \
+ or not model.categories_json \
+ or not isinstance(model.categories_json, dict) \
+ or not getattr(config,'LDT_PLATFORM_BASE_URL',None):
+ return ''
+
+ output = []
+
+ for c in model.categories_json.get("categories",[]):
+ if "subcategories" in c and len(c["subcategories"])>0:
+ for sc in c["subcategories"]:
+ output.append({"name": sc["code"],"keywords": [ sc["label"] ], "color" : sc["color"] })
+ else:
+ output.append({"name": c["code"],"keywords": [ c["label"] ], "color" : c["color"] })
+
+ base_url = getattr(config,'LDT_PLATFORM_BASE_URL','') + "/ldt/embediframe/?"
+ url_query_params = {'project_id': model.project_id, 'polemic': 'all', 'polemics_list': json.dumps(output, separators=(',',':'))}
+
+ url = base_url + urllib.urlencode(url_query_params)
+
+ return Markup("<a href=\"%s\" target=\"_blank\">%s</a>" % (url,url[:80]+"..."))
+
+
+class EventView(ModelView):
+ column_searchable_list = ('code', 'label')
+ column_list = ('code', 'label', 'start_date', 'active')
+ column_filters = ('code', 'label', 'start_date', 'active')
+ form_create_rules = ('code', 'label', 'description', 'start_date')
+ inline_models = (models.EventSession,)
+ #form_edit_rules = ('label', 'description', 'start_date', 'active', 'code')
+
+ def __init__(self, session, **kwargs):
+ super(EventView, self).__init__(models.Event, session, **kwargs)
+
+
+class DictToJSONField(fields.TextAreaField):
+ def process_data(self, value):
+ if value is None:
+ value = {}
+
+ self.data = json.dumps(value, indent=2)
+
+ def process_formdata(self, valuelist):
+ if valuelist:
+ self.data = json.loads(valuelist[0])
+ else:
+ self.data = '{}'
+
+class JsonAdminConverter(AdminModelConverter):
+ @converts('JSON')
+ def conv_JSON(self, field_args, **extra):
+ return DictToJSONField(**field_args)
+
+class EventSessionView(ModelView):
+
+ column_default_sort = ( models.Event.code, True)
+ column_sortable_list = (('event', models.Event.code),)
+ column_auto_select_related = True
+ column_list = ('event', 'project_id', 'order', 'categories_json', 'url')
+ column_filters = ('event',)
+ column_formatters = {'url': build_ldt_url, 'categories_json': lambda v, c, m, p: json.dumps(m.categories_json)[:80] if m.categories_json else ''}
+
+ model_form_converter=JsonAdminConverter
+
+ def __init__(self, session, **kwargs):
+ super(EventSessionView, self).__init__(models.EventSession, session, **kwargs)
+
+
+
+admin.add_view(EventView(database.db_session))
+admin.add_view(EventSessionView(database.db_session))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/annot-server/webapp/templates/broadcast.html Mon Oct 20 01:31:33 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>
--- a/annot-server/webapp/templates/index.html Sun Oct 19 12:52:38 2014 +0200
+++ b/annot-server/webapp/templates/index.html Mon Oct 20 01:31:33 2014 +0200
@@ -1,56 +1,23 @@
-<!DOCTYPE html>
+<!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>
+<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/base.css">
+</head>
+<body>
+ <div class="container" id="index-container">
+ <h1 class="row">Évènements actifs :</h1>
+ {% for event in events %}
+ <div class="row">
+ <div class="event-label"><a href="{{ url_for('page_annotationclient_event_code', event_code=event.code) }}">{{ event.label }}</a></div>
+ <dl>
+ <dt>Code : {{ event.code }}</dt>
+ <dd>Description : {{ event.description }}</dd>
+ </dl>
+ </div>
+ {% endfor %}
+ </div>
+ </body>
--- a/annot-server/webapp/views.py Sun Oct 19 12:52:38 2014 +0200
+++ b/annot-server/webapp/views.py Mon Oct 20 01:31:33 2014 +0200
@@ -15,8 +15,8 @@
@app.route('/')
def page_home():
- return render_template('index.html')
- #return render_template('annotationclient.html', logging=True)
+ events = db_session.query(models.Event).filter(models.Event.active == True).order_by(models.Event.start_date, models.Event.code).all()
+ return render_template('index.html', events=events)
@app.route('/annot')
@@ -31,8 +31,9 @@
@app.route('/annotationclient/<event_code>')
def page_annotationclient_event_code(event_code):
#TODO: check event code + get event session
- event_query = db_session.query(models.Event).filter(models.Event.code==event_code)
+ event_query = db_session.query(models.Event).filter(models.Event.code == event_code, models.Event.active == True)
event = event_query.one()
+
if not event:
abort(404)
--- a/utils/export_annotations.py Sun Oct 19 12:52:38 2014 +0200
+++ b/utils/export_annotations.py Mon Oct 20 01:31:33 2014 +0200
@@ -52,31 +52,6 @@
res.append({'name': 'user', 'op': "in", 'val':user_whitelist })
return res
-# def parse_polemics(tw, extended_mode):
-# """
-# parse polemics in text and return a list of polemic code. None if not polemic found
-# """
-# polemics = {}
-# for m in re.finditer("(\+\+|\-\-|\?\?|\=\=)",tw.text):
-# pol_link = {
-# '++' : u'OK',
-# '--' : u'KO',
-# '??' : u'Q',
-# '==' : u'REF'}[m.group(1)]
-# polemics[pol_link] = pol_link
-#
-# if extended_mode:
-# if "?" in tw.text:
-# polemics["Q"] = "Q"
-#
-# for entity in tw.entity_list:
-# if entity.type == "entity_url":
-# polemics["REF"] = "REF"
-#
-# if len(polemics) > 0:
-# return polemics.keys()
-# else:
-# return None
def set_logging(options, plogger=None, queue=None):