From ba1343dafa74a4a7d6bc697047ce96602f056ac6 Mon Sep 17 00:00:00 2001
From: YSelf Tool <yselftool@gmail.com>
Date: Fri, 11 Sep 2015 19:07:49 +0200
Subject: [PATCH] Changed mode to sorting type, implemented balanced and fifo

---
 models/database.py                 | 14 +++----
 models/forms.py                    |  2 +-
 modules/admin.py                   |  3 +-
 modules/speech.py                  | 65 +++++++++++++++++-------------
 server.py                          |  8 ++--
 templates/admin_event_index.html   |  4 +-
 templates/admin_index.html         |  4 +-
 templates/content_index.html       | 14 +------
 templates/layout.html              |  6 +--
 templates/speech_content_show.html | 32 +++------------
 templates/speech_index.html        |  6 ++-
 templates/update.js                | 38 ++++++++---------
 12 files changed, 88 insertions(+), 108 deletions(-)

diff --git a/models/database.py b/models/database.py
index be72003..5f72d62 100644
--- a/models/database.py
+++ b/models/database.py
@@ -38,19 +38,19 @@ class Event(db.Model):
     __tablename__ = "events"
     id = db.Column(db.Integer, primary_key=True)
     name = db.Column(db.String, unique=True)
-    date = db.Column(db.Date)
+    mode = db.Column(db.String)
     
-    def __init__(self, name, date):
+    def __init__(self, name, mode):
         self.name = name
-        self.date = date
+        self.mode = mode
     
     def __repr__(self):
-        return "<Event(id={}, name='{}', date={})>".format(
+        return "<Event(id={}, name='{}', mode='{}')>".format(
             self.id, 
             self.name, 
-            self.date
+            self.mode
         )
-
+    
 
 class Speaker(db.Model):
     __tablename__ = "speakers"
@@ -63,7 +63,7 @@ class Speaker(db.Model):
         self.event = event
     
     def __repr__(self):
-        return "<Speaker(id={}, name={}, event={})>".format(
+        return "<Speaker(id={}, name='{}', event={})>".format(
             self.id, 
             self.name,
             self.event
diff --git a/models/forms.py b/models/forms.py
index 5a1072e..146488d 100644
--- a/models/forms.py
+++ b/models/forms.py
@@ -28,4 +28,4 @@ class AddStatementForm(Form):
 
 class NewEventForm(Form):
     name = StringField("Name", validators=[InputRequired("Entering the name is required.")])
-    date = DateField("Date (DD.MM.YYYY)", validators=[InputRequired("Entering the date is required.")], format="%d.%m.%Y")
+    mode = StringField("Mode", validators=[InputRequired("Entering the mode is required."), AnyOf(values=["balanced", "fifo"], message="Must be 'balanced' or 'fifo' atm.")])
diff --git a/modules/admin.py b/modules/admin.py
index d18ca5c..74efba1 100644
--- a/modules/admin.py
+++ b/modules/admin.py
@@ -78,7 +78,7 @@ def event_new():
         if Event.query.filter_by(name=form.name.data).count() > 0:
             flash("There already is an event with that name.", "alert-error")
             return render_layout("admin_event_new.html", form=form)
-        event = Event(form.name.data, form.date.data)
+        event = Event(form.name.data, form.mode.data)
         db.session.add(event)
         db.session.commit()
         return redirect(url_for(".event"))
@@ -118,5 +118,4 @@ def event_edit():
 @admin_permission.require()
 def event():
     events = Event.query.all()
-    print(events)
     return render_layout("admin_event_index.html", events=events)
diff --git a/modules/speech.py b/modules/speech.py
index 56b2bb4..e7a62a9 100644
--- a/modules/speech.py
+++ b/modules/speech.py
@@ -13,62 +13,73 @@ import config
 
 speech = Blueprint("speech", __name__)
 
-def transpose(arr):
-    print(list)
-    return list(map(list, zip(*arr)))
-
 def query_statements(mode, event_id):
-    statements = []
-    if mode == "pending":
-        statements = db.session.query(Statement, Speaker, db.func.count(Statement.speaker).label("total")).group_by(Speaker.id).join(Speaker).filter(Statement.event == event_id).order_by("total ASC", Statement.insertion_time).all()
-    elif mode == "all":
-        statements = db.session.query(Statement, Speaker).join(Speaker).filter(Statement.event == event_id).order_by(Statement.insertion_time).all()
-    elif mode == "past":
-        statements = db.session.query(Statement, Speaker).join(Speaker).filter(Statement.executed == True).filter(Statement.event == event_id).order_by(Statement.execution_time).all()
-    return statements
+    statements = db.session.query(Statement).filter_by(event=event_id).all()
+    speakers = db.session.query(Speaker).filter_by(event=event_id).all()
+    if mode == "balanced" or mode == "pending":
+        count = { speaker.id: 0 for speaker in speakers }
+        for statement in statements:
+            if statement.speaker in count:
+                count[statement.speaker] += 1
+            else:
+                count[statement.speaker] = 1
+        sorted_speakers = sorted(speakers, key=lambda sp: count[sp.id])
+        result = []
+        for speaker in sorted_speakers:
+            pending_statements = [statement for statement in statements if statement.speaker == speaker.id and not statement.executed]
+            if len(pending_statements) > 0:
+                result.append((pending_statements[0], speaker, count[speaker.id]))
+        return result
+    
+    if mode == "fifo":
+        speaker_by_id = { speaker.id: speaker for speaker in speakers }
+        result = [(statement, speaker_by_id[statement.speaker], 0) for statement in statements if not statement.executed]
+        return result
+    
+    print("unknown querying mode {}".format(mode))
 
 @speech.route("/index")
 def index():
-    mode = request.args.get("mode", "pending")
     event_id = request.args.get("event", None) 
+    mode = request.args.get("mode", None)
     meta = []
     if event_id is not None and event_id != "-1":
         event = Event.query.filter_by(id=event_id).first()
         form = AddStatementForm()
         form.event.data = event.id
-        meta.append((query_statements(mode, event_id), form, event))
+        meta.append((query_statements(mode if mode is not None else event.mode, event_id), form, event))
     else:
         for event in Event.query.all():
             form = AddStatementForm()
             form.event.data = event.id
-            meta.append((query_statements(mode, event.id), form, event))
+            meta.append((query_statements(mode if mode is not None else event.mode, event.id), form, event))
         event_id = -1
-    return render_layout("speech_index.html", meta=meta, event_id=event_id)
+    return render_layout("speech_index.html", meta=meta, event_id=event_id, mode=mode)
 
 @speech.route("/show")
 def show():
-    mode = request.args.get("mode", "pending") 
     event_id = request.args.get("event", None)
+    mode = request.args.get("mode", None) 
     meta = []
     if event_id is not None and event_id is not "-1":
         event = Event.query.filter_by(id=event_id).first()
-        meta.append((query_statements(mode, event_id), event))
+        meta.append((query_statements(mode if mode is not None else event.mode, event_id), event))
     else:
         for event in Event.query.all():
-            meta.append((query_statements(mode, event.id), event))
+            meta.append((query_statements(mode if mode is not None else event.mode, event.id), event))
     return render_layout("speech_show.html", mode=mode, meta=meta, event_id=event_id)
 
 @speech.route("/update")
 def update():
-    mode = request.args.get("mode", "pending") 
     event_id = request.args.get("event", None)
+    mode = request.args.get("mode", None) 
     meta = []
     if event_id is not None and event_id != "-1":
         event = Event.query.filter_by(id=event_id).first()
-        meta.append((query_statements(mode, event_id), event))
+        meta.append((query_statements(mode if mode is not None else event.mode, event_id), event))
     else:
         for event in Event.query.all():
-            meta.append((query_statements(mode, event.id), event))
+            meta.append((query_statements(mode if mode is not None else event.mode, event.id), event))
     return render_layout("speech_content_show.html", mode=mode, meta=meta)
 
 
@@ -94,7 +105,7 @@ def add():
     statement = Statement(speaker.id, event_id)
     db.session.add(statement)
     db.session.commit()
-    mode = request.args.get("mode", "pending")
+    mode = request.args.get("mode", None)
     event_id = request.args.get("event", None)
     return redirect(url_for(request.args.get("next") or ".index", mode=mode, event=event_id))
 
@@ -111,7 +122,7 @@ def cancel():
     db.session.delete(statement)
     db.session.commit()
     flash("Statement canceled", "alert-success")
-    mode = request.args.get("mode", "pending")
+    mode = request.args.get("mode", None)
     return redirect(url_for(request.args.get("next") or ".index", mode=mode, event=event_id))
 
 @speech.route("/done")
@@ -127,15 +138,15 @@ def done():
         db.session.commit()
     else:
         flash("Statement already done", "alert-error")
-    mode = request.args.get("mode", "pending")
+    mode = request.args.get("mode", None)
     return redirect(url_for(request.args.get("next") or ".index", mode=mode, event=event_id))
 
 @speech.route("/update_show.js")
 def update_show_js():
     update_interval = config.UPDATE_SHOW_INTERVAL or 1
     div = "rede-content-div"
-    mode = request.args.get("mode", "pending")
+    mode = request.args.get("mode", None)
     event_id = request.args.get("event", -1)
     target_url = url_for(".update", mode=mode, event=event_id)
-    return render_layout("update.js", update_interval=update_interval, div=div, target_url=target_url)
+    return render_layout("update.js", update_interval=update_interval, div=div, target_url=target_url, prefix="update_show_")
 
diff --git a/server.py b/server.py
index 42c4241..e08a739 100755
--- a/server.py
+++ b/server.py
@@ -37,7 +37,7 @@ def index():
     events = Event.query.all()
     meta = []
     for event in events:
-        ls = [ (statement, speaker, count) for (statement, speaker, count) in speech.query_statements("pending", event.id) if not statement.executed ]
+        ls = speech.query_statements(event.mode, event.id)
         no_speaker = Speaker("No Speaker", event)
         no_statement = Statement(no_speaker, event)
         meta.append((ls[0] if len(ls) > 0 else (no_statement, no_speaker, ()), event))
@@ -48,7 +48,7 @@ def update():
     events = Event.query.all()
     meta = []
     for event in events:
-        ls = [ (statement, speaker, count) for (statement, speaker, count) in speech.query_statements("pending", event.id) if not statement.executed ]
+        ls = speech.query_statements(event.mode, event.id)
         no_speaker = Speaker("No Speaker", event)
         no_statement = Statement(no_speaker, event)
         meta.append((ls[0] if len(ls) > 0 else (no_statement, no_speaker, ()), event))
@@ -59,7 +59,7 @@ def update_js():
     update_interval = config.UPDATE_INDEX_INTERVAL or 1
     div = "rede-content-div"
     target_url = url_for(".update")
-    return render_layout("update.js", update_interval=update_interval, div=div, target=target_url)
+    return render_layout("update.js", update_interval=update_interval, div=div, target_url=target_url, prefix="index_")
 
 @app.route("/update_time")
 def update_time():
@@ -70,7 +70,7 @@ def update_time_js():
     update_interval = config.UPDATE_TIME_INTERVAL or 10
     div = "rede-time-div"
     target_url = url_for("update_time")
-    return render_layout("update.js", update_interval=update_interval, div=div, target_url=target_url)
+    return render_layout("update.js", update_interval=update_interval, div=div, target_url=target_url, prefix="time_")
 
 @app.route("/login", methods=["GET", "POST"])
 def login():
diff --git a/templates/admin_event_index.html b/templates/admin_event_index.html
index 63e5887..0bdd1d5 100644
--- a/templates/admin_event_index.html
+++ b/templates/admin_event_index.html
@@ -7,7 +7,7 @@
             <thead>
                 <tr>
                     <th class="mdl-data-table__cell--non-numeric">Name</th>
-                    <th class="mdl-data-table__cell--non-numeric">Date</th>
+                    <th class="mdl-data-table__cell--non-numeric">Mode</th>
                     <th class="mdl-data-table__cell--non-numeric">Delete</th>
                 </tr>
             </thead>
@@ -15,7 +15,7 @@
             {% for event in events %}
                 <tr>
                     <td class="mdl-data-table__cell--non-numeric"><a href="{{ url_for(".event_edit", id=event.id) }}">{{ event.name }}</a></td>
-                    <td class="mdl-data-table__cell--non-numeric">{{ event.date.strftime("%d.%m.%Y") }}</td>
+                    <td class="mdl-data-table__cell--non-numeric">{{ event.mode }}</td>
                     <td class="mdl-data-table__cell--non-numeric">
                         <a href="{{ url_for('.event_delete', id=event.id) }}">
                             <i class="material-icons">delete</i>
diff --git a/templates/admin_index.html b/templates/admin_index.html
index 138ddc2..3c32164 100644
--- a/templates/admin_index.html
+++ b/templates/admin_index.html
@@ -32,14 +32,14 @@
             <thead>
                 <tr>
                     <th class="mdl-data-table__cell--non-numeric">Name</th>
-                    <th class="mdl-data-table__cell--non-numeric">Date</th>
+                    <th class="mdl-data-table__cell--non-numeric">Mode</th>
                 </tr>
             </thead>
             <tbody>
             {% for event in events %}
                 <tr>
                     <td class="mdl-data-table__cell--non-numeric"><a href="{{ url_for(".event_edit", id=event.id) }}">{{ event.name }}</a></td>
-                    <td class="mdl-data-table__cell--non-numeric">{{ event.date.strftime("%d.%m.%Y") }}</td>
+                    <td class="mdl-data-table__cell--non-numeric">{{ event.mode }}</td>
                 </tr>
             {% endfor %}
             </tbody>
diff --git a/templates/content_index.html b/templates/content_index.html
index fe78097..b076ce5 100644
--- a/templates/content_index.html
+++ b/templates/content_index.html
@@ -5,27 +5,17 @@
         </div>
         <div class="mdl-card__actions">
             {% if current_user.is_authenticated() and "user" in current_user.roles %}
-            <a href="{{ url_for("speech.index", event=event.id, mode="pending") }}">
+            <a href="{{ url_for("speech.index", event=event.id) }}">
                 <button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
                     <i class="material-icons" role="presentation">build</i>
                 </button>
             </a>
             {% endif %}
-            <a href="{{ url_for("speech.show", event=event.id, mode="pending") }}">
-                <button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
-                    <i class="material-icons" role="presentation">announcement</i>
-                </button>
-            </a>
-            <a href="{{ url_for("speech.show", event=event.id, mode="all") }}">
+            <a href="{{ url_for("speech.show", event=event.id) }}">
                 <button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
                     <i class="material-icons" role="presentation">list</i>
                 </button>
             </a>
-            <a href="{{ url_for("speech.show", event=event.id, mode="past") }}">
-                <button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
-                    <i class="material-icons" role="presentation">schedule</i>
-                </button>
-            </a>
         </div>
     </div>
     {% endfor %}
diff --git a/templates/layout.html b/templates/layout.html
index ddb82e4..6836e6a 100644
--- a/templates/layout.html
+++ b/templates/layout.html
@@ -78,11 +78,9 @@
         </header>
         <nav class="rede-navigation mdl-navigation mdl-color--blue-grey-800">
             {% if current_user.is_authenticated() and "user" in current_user.roles %}
-            <a class="mdl-navigation__link" href="{{ url_for("speech.index", mode="pending") }}"><i class="mdl-color-text--blue-grey-400 material-icons" role="presentation">build</i>Handle speakers</a>
+            <a class="mdl-navigation__link" href="{{ url_for("speech.index") }}"><i class="mdl-color-text--blue-grey-400 material-icons" role="presentation">build</i>Handle speakers</a>
             {% endif %}
-            <a class="mdl-navigation__link" href="{{ url_for("speech.show", mode="pending") }}"><i class="mdl-color-text--blue-grey-400 material-icons" role="presentation">announcement</i>Pending speakers</a>
-            <a class="mdl-navigation__link" href="{{ url_for("speech.show", mode="all") }}"><i class="mdl-color-text--blue-grey-400 material-icons" role="presentation">list</i>All speakers</a>
-            <a class="mdl-navigation__link" href="{{ url_for("speech.show", mode="past") }}"><i class="mdl-color-text--blue-grey-400 material-icons" role="presentation">schedule</i>Past speakers</a>
+            <a class="mdl-navigation__link" href="{{ url_for("speech.show") }}"><i class="mdl-color-text--blue-grey-400 material-icons" role="presentation">announcement</i>Pending speakers</a>
             {% if current_user.is_authenticated() and "admin" in current_user.roles %}
             <a class="mdl-navigation__link" href="{{ url_for("admin.index") }}"><i class="mdl-color-text--blue-grey-400 material-icons" role="presentation">computer</i>Administration</a>
             {% endif %}
diff --git a/templates/speech_content_show.html b/templates/speech_content_show.html
index 6eb69c8..94c8a61 100644
--- a/templates/speech_content_show.html
+++ b/templates/speech_content_show.html
@@ -4,40 +4,18 @@
             <thead>
                 <tr>
                     <th class="mdl-data-table__cell--non-numeric">Speaker for {{ event.name }}</th>
-                    {% if mode == "all" or mode == "past" %}
-                    <th class="mdl-data-table__cell--non-numeric">Time</th>
-                    {% endif %}
                 </tr>
             </thead>
             <tbody>
-            {% if mode == "all" or mode == "past" %}
-                {% for statement, speaker in statements %}
+            {% for statement, speaker, count in statements %}
+                {% if not statement.executed %}
                     <tr>
                         <td class="mdl-data-table__cell--non-numeric">
-                            {{ speaker.name }}
+                            <h5>{{ speaker.name }}</h5>
                         </td>
-                        {% if mode == "all" %}
-                        <td class="mdl-data-table__cell--non-numeric">
-                            {{ statement.insertion_time.strftime("%d. %B %Y, %H:%M") }}
-                        </td>
-                        {% elif mode == "past" %}
-                        <td class="mdl-data-table__cell--non-numeric">
-                            {{ statement.execution_time.strftime("%d. %B %Y, %H:%M") }}
-                        </td>
-                        {% endif %}
                     </tr>
-                {% endfor %}
-            {% elif mode == "pending" %}
-                {% for statement, speaker, count in statements %}
-                    {% if not statement.executed %}
-                        <tr>
-                            <td class="mdl-data-table__cell--non-numeric">
-                                <h5>{{ speaker.name }}</h5>
-                            </td>
-                        </tr>
-                    {% endif %}
-                {% endfor %}
-            {% endif %}
+                {% endif %}
+            {% endfor %}
             </tbody>
         </table>
     {% endfor %}
diff --git a/templates/speech_index.html b/templates/speech_index.html
index ebd02b7..ad81430 100644
--- a/templates/speech_index.html
+++ b/templates/speech_index.html
@@ -8,7 +8,9 @@
             <thead>
                 <tr>
                     <th class="mdl-data-table__cell--non-numeric">Speaker</th>
+                    {% if (mode is not none and mode == "balanced") or (mode is none and event.mode == "balanced") %}
                     <th>Count</th>
+                    {% endif %}
                     {% if "user" in current_user.roles %}
                     <th class="mdl-data-table__cell--non-numeric">Done</th>
                     <th class="mdl-data-table__cell--non-numeric">Cancel</th>
@@ -17,14 +19,15 @@
             </thead>
             <tbody>
             {% for statement, speaker, count in statements %}
-                {% if not statement.executed %}
                 <tr>
                     <td class="mdl-data-table__cell--non-numeric">
                         <h5>{{ speaker.name }}</h5>
                     </td>
+                    {% if (mode is not none and mode == "balanced") or (mode is none and event.mode == "balanced") %}
                     <td>
                         <h5>{{ count }}</h5>
                     </td>
+                    {% endif %}
                     {% if "user" in current_user.roles %}
                     <td class="mdl-data-table__cell--non-numeric">
                         <a href="{{ url_for(".done", statement=statement.id, next=".index", event=event_id) }}">
@@ -42,7 +45,6 @@
                     </td>
                     {% endif %}
                 </tr>
-                {% endif %}
             {% endfor %}
             </tbody>
         </table>
diff --git a/templates/update.js b/templates/update.js
index c6634de..6246d0f 100644
--- a/templates/update.js
+++ b/templates/update.js
@@ -1,29 +1,31 @@
-var returned = true;
-var last_content = "";
-function request() {
-    if (!returned)
+var {{ prefix }}returned = true;
+var {{ prefix }}last_content = "";
+function {{ prefix }}request() {
+    if (!{{ prefix }}returned)
         return;
-    returned = false;
-    var xmlhttp = new XMLHttpRequest();
-    xmlhttp.onreadystatechange=function() {
-        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
-            returned = true;
-            update(xmlhttp.responseText);
+    {{ prefix }}returned = false;
+    var {{ prefix }}xmlhttp = new XMLHttpRequest();
+    {{ prefix }}xmlhttp.onreadystatechange=function() {
+        if ({{ prefix }}xmlhttp.readyState == 4 && {{ prefix }}xmlhttp.status == 200) {
+            {{ prefix }}returned = true;
+            {{ prefix }}update({{ prefix }}xmlhttp.responseText);
         }
     };
-    var target = "{{ target_url }}";
-    xmlhttp.open("GET", target, true);
-    xmlhttp.send();
+    var {{ prefix }}target = "{{ target_url }}";
+    {{ prefix }}xmlhttp.open("GET", {{ prefix }}target, true);
+    {{ prefix }}xmlhttp.send();
 }
 
-function update(data) {
-    if (data != last_content) {
-        document.getElementById("{{ div }}").innerHTML = data;
-        last_content = data;
+function {{ prefix }}update({{ prefix }}data) {
+    if ({{ prefix }}data != {{ prefix }}last_content) {
+        document.getElementById("{{ div }}").innerHTML = {{ prefix }}data;
+        {{ prefix }}last_content = {{ prefix }}data;
     }
 }
 
+var {{ prefix }}f = window.onload;
 window.onload=function() {
-    window.setInterval(request, 1000 * {{ update_interval }});
+    {{ prefix }}f();
+    window.setInterval({{ prefix }}request, 1000 * {{ update_interval }});
 }
 
-- 
GitLab