end of admin. change the index page and add a redirect to it on the landing page
authorymh <ymh.work@gmail.com>
Mon, 20 Oct 2014 01:31:33 +0200
changeset 43 e27c3c1c57f1
parent 42 926f0426ce78
child 44 76f2fa4eb4f7
end of admin. change the index page and add a redirect to it on the landing page
annot-server/annotserver.py
annot-server/models.py
annot-server/static/css/base.css
annot-server/webapp/admin.py
annot-server/webapp/templates/broadcast.html
annot-server/webapp/templates/index.html
annot-server/webapp/views.py
utils/export_annotations.py
--- 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&nbsp;:</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&nbsp;: {{ event.code }}</dt>
+              <dd>Description&nbsp;: {{ 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):