Commit c76c322c authored by YSelf Tool's avatar YSelf Tool

Implemented balanced queue

parent ad2cb155
from flask.ext.login import UserMixin
from datetime import datetime
from shared import db
class User(db.Model, UserMixin):
......@@ -9,12 +11,71 @@ class User(db.Model, UserMixin):
username = db.Column(db.String, unique=True)
password = db.Column(db.String)
roles = db.Column(db.PickleType)
temp_key = db.Column(db.String)
temp_key_timestamp = db.Column(db.DateTime)
def __init__(self, fullname, username, password, roles=None):
self.fullname = fullname
self.username = username
self.password = password
self.roles = roles
self.temp_key = ""
self.temp_key_timestamp = datetime(1970, 1, 1, 0, 0)
def __repr__(self):
return "<User(id={}, fullname='{}', username='{}', password'{}', roles{}, temp_key='{}', temp_key_timestamp={})>".format(
self.id,
self.fullname,
self.username,
self.password,
self.roles,
self.temp_key,
self.temp_key_timestamp
)
class Speaker(db.Model):
__tablename__ = "speakers"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, unique=True)
def __init__(self, name):
self.name = name
def __repr__(self):
return "<Speaker(id={}, name={})>".format(self.id, self.name)
class Statement(db.Model):
__tablename__ = "statements"
id = db.Column(db.Integer, primary_key=True)
speaker = db.Column(db.Integer, db.ForeignKey("speakers.id"), nullable=False)
insertion_time = db.Column(db.DateTime)
executed = db.Column(db.Boolean)
execution_time = db.Column(db.DateTime)
def __init__(self, speaker, insertion_time=None, executed=False, execution_time=None):
self.speaker = speaker
self.insertion_time = insertion_time or datetime.now()
self.executed = executed
self.execution_time = execution_time or datetime.now()
def __repr__(self):
return "<User(id={}, fullname='{}', username='{}', password'{}', roles'{})>".format(self.id, self.fullname, self.username, self.password, self.roles)
return "<Statement(id={}, speaker={}, insertion_time={}, executed={}, execution_time={})>".format(
self.id,
self.speaker,
self.insertion_time,
self.executed,
self.execution_time
)
def dump(self):
return { "speaker": self.speaker, "insertion_time": self.insertion_time.timestamp(), "executed": self.executed, "execution_time": self.execution_time.timestamp() }
def done(self):
if self.executed:
return False
self.executed = True
self.execution_time = datetime.now()
return True
......@@ -21,3 +21,6 @@ class AdminUserForm(Form):
fullname = StringField("Full name", validators=[InputRequired("Entering the name is required.")])
username = StringField("Username", validators=[InputRequired("Entering the username is required.")])
roles = SelectMultipleField("User roles", choices=[(x.lower().strip(), x) for x in shared.roles])
class AddStatementForm(Form):
speaker_name = StringField("Speaker", validators=[InputRequired("Entering the speaker is required.")])
from flask import Blueprint, render_template, redirect, url_for, request, flash, abort, send_file, Response
from flask.ext.login import login_required
from models.database import User, Statement, Speaker
from models.forms import AddStatementForm
from shared import db, admin_permission, user_permission
from datetime import datetime
import json
speech = Blueprint("speech", __name__)
def transpose(arr):
print(list)
return list(map(list, zip(*arr)))
def query_statements(mode):
statements = []
if mode == "pending":
statements = db.session.query(Statement, Speaker, db.func.count(Statement.speaker).label("total")).group_by(Speaker.id).join(Speaker).order_by("total ASC", Statement.insertion_time).all()
elif mode == "all":
statements = db.session.query(Statement, Speaker).join(Speaker).order_by(Statement.insertion_time).all()
elif mode == "past":
statements = db.session.query(Statement, Speaker).join(Speaker).filter(Statement.executed == True).order_by(Statement.execution_time).all()
return statements
@speech.route("/index")
def index():
mode = request.args.get("mode", "pending")
statements = query_statements(mode)
add_form = AddStatementForm()
current = ".index"
return render_template("speech_index.html", statements=statements, add_form=add_form, current=current)
@speech.route("/show")
def show():
mode = request.args.get("mode", "pending")
statements = query_statements(mode)
current = ".show"
return render_template("speech_show.html", statements=statements, current=current, mode=mode)
@speech.route("/update")
def update():
mode = request.args.get("mode", "pending")
statements = query_statements(mode)
return render_template("speech_update_show.html", statements=statements, mode=mode)
@speech.route("/add", methods=["GET", "POST"])
@user_permission.require()
def add():
speaker_name = request.args.get("speaker", None)
add_form = AddStatementForm()
if add_form.validate_on_submit():
speaker_name = add_form["speaker_name"].data
if speaker_name is None:
flash("Missing speaker name", "alert-error")
return redirect(url_for(".show"))
speaker = Speaker.query.filter_by(name=speaker_name).first()
if not speaker:
speaker = Speaker(speaker_name)
db.session.add(speaker)
db.session.commit()
if Statement.query.filter_by(speaker=speaker.id).filter_by(executed=False).count() > 0:
flash("Speaker already listet", "alert-error")
return redirect(url_for(request.args.get("next") or ".show"))
statement = Statement(speaker.id)
db.session.add(statement)
db.session.commit()
mode = request.args.get("mode", "pending")
return redirect(url_for(request.args.get("next") or ".index", mode=mode))
@speech.route("/cancel")
@user_permission.require()
def cancel():
statement_id = request.args.get("statement", None)
if not statement_id:
flash("Missing statement id", "alert-error")
return redirect(url_for(request.args.get("next") or ".index"))
statement = Statement.query.filter_by(id=statement_id).first()
db.session.delete(statement)
db.session.commit()
flash("Statement canceled", "alert-success")
mode = request.args.get("mode", "pending")
return redirect(url_for(request.args.get("next") or ".index", mode=mode))
@speech.route("/done")
@user_permission.require()
def done():
statement_id = request.args.get("statement", None)
if not statement_id:
flash("Missing statement id", "alert-error")
return redirect(url_for(request.args.get("next") or ".index"))
statement = Statement.query.filter_by(id=statement_id).first()
if statement.done():
db.session.commit()
else:
flash("Statement already done", "alert-error")
mode = request.args.get("mode", "pending")
return redirect(url_for(request.args.get("next") or ".index", mode=mode))
@speech.route("/update_show.js")
def update_show_js():
mode = request.args.get("mode", "pending")
return render_template("update_show.js", mode=mode)
......@@ -7,8 +7,8 @@ from passlib.hash import pbkdf2_sha256
import config
from shared import db, login_manager
from models.forms import LoginForm
from models.database import User
from models.forms import LoginForm, NewUserForm
from models.database import User, Statement, Speaker
app = Flask(__name__)
app.config.from_object(config)
......@@ -19,9 +19,10 @@ login_manager.login_message_category = "alert-error"
Principal(app)
from modules import admin
from modules import admin, speech
app.register_blueprint(admin.admin, url_prefix="/admin")
app.register_blueprint(speech.speech, url_prefix="/speech")
db.create_all(app=app)
@app.route("/")
......@@ -33,7 +34,8 @@ def index():
user = User(fullname, username, password, ["admin", "user"])
db.session.add(user)
db.session.commit()
return render_template("index.html")
#return render_template("index.html")
return redirect(url_for("speech.show", mode="pending"))
@app.route("/login", methods=["GET", "POST"])
def login():
......@@ -75,7 +77,6 @@ def register():
return redirect(url_for(".login"))
return render_template("register.html", form=form)
@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
# Set the identity user object
......
......@@ -97,3 +97,11 @@
.rede-separator {
height: 32px;
}
.md-24 {
font-size: 24px;
}
.md-48 {
font-size: 48px;
}
{% extends "layout.html" %}
{% block title %}Index{% endblock %}
{% block title %}{% block admin_title %}Index{% endblock %} - Administration{% endblock %}
{% block content %}
<table class="mdl-data-table mdl-js-table mdl-shadow--2dp sortable mdl-cell mdl-cell--3-col">
<thead>
<tr>
<th class="mdl-data-table_-cell--non-numeric">Full Name</th>
<th class="mdl-data-table_-cell--non-numeric">Username</th>
<th class="mdl-data-table_-cell--non-numeric">Roles</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td class="mdl-data-table__cell--non-numeric"><a href="{{ url_for(".user_edit", id=user.id) }}">{{ user.fullname }}</a></td>
<td class="mdl-data-table__cell--non-numeric">{{ user.username }}</td>
<td class="mdl-data-table__cell--non-numeric">{% if user.roles is not none %}{{ ", ".join(user.roles) }}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="mdl-card__actions">
<a class="mdl-button mdl-button--colored mdl-js-button" href="{{ url_for(".user") }}">All users</a>
<div class="mdl-cell mdl-cell--6-col mdl-cell--8-col-tablet mdl-cell--4-col-phone mdl-grid mdl-grid--no-spacing">
<table class="mdl-data-table mdl-js-table mdl-shadow--2dp sortable mdl-cell mdl-cell--12-col mdl-cell--8-col-tablet mdl-cell--4-col-phone">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">Full Name</th>
<th class="mdl-data-table__cell--non-numeric">Username</th>
<th class="mdl-data-table__cell--non-numeric">Roles</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td class="mdl-data-table__cell--non-numeric"><a href="{{ url_for(".user_edit", id=user.id) }}">{{ user.fullname }}</a></td>
<td class="mdl-data-table__cell--non-numeric">{{ user.username }}</td>
<td class="mdl-data-table__cell--non-numeric">{% if user.roles is not none %}{{ ", ".join(user.roles) }}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="mdl-cell mdl-cell--3-col mdl-cell--3-col-tablet mdl-cell--2-col-phone">
<a class="mdl-button mdl-button--colored mdl-js-button" href="{{ url_for(".user") }}">
All users
</a>
</div>
</div>
{% endblock %}
{% extends "layout.html" %}
{% block title %}Index{% endblock %}
{% extends "admin_index.html" %}
{% block admin_title %}Users{% endblock %}
{% block content %}
<div class="mdl-cell mdl-cell--3-col mdl-grid mdl-grid--no-spacing">
<table class="mdl-data-table mdl-js-table mdl-shadow--2dp mdl-cell mdl-cell--3-col">
<thead>
<tr>
<th class="mdl-data-table_-cell--non-numeric">Full Name</th>
<th class="mdl-data-table_-cell--non-numeric">Username</th>
<th class="mdl-data-table_-cell--non-numeric">Roles</th>
<th class="mdl-data-table_-cell--non-numeric">Delete</th>
<th class="mdl-data-table__cell--non-numeric">Full Name</th>
<th class="mdl-data-table__cell--non-numeric">Username</th>
<th class="mdl-data-table__cell--non-numeric">Roles</th>
<th class="mdl-data-table__cell--non-numeric">Delete</th>
</tr>
</thead>
<tbody>
......
......@@ -12,6 +12,9 @@
<meta name="mobile-web-app-capable" content="yes">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
<title>{% block title %}Unknown Page{% endblock %} - Redeleitsystem</title>
{% block additional_js %}
<!-- Place to insert more .js-files -->
{% endblock %}
{% endblock %}
</head>
<body>
......@@ -35,16 +38,29 @@
<div class="rede-account-dropdown">
<span>
{% if current_user.is_authenticated() %}
{{ current_user.fullname }}
<p class="md-24">
<i class="material-icons md-48">
{% if "user" in current_user.roles and not "admin" in current_user.roles %}
person_outline
{% elif "admin" in current_user.roles %}
person
{% else %}
face
{% endif %}</i>
{{ current_user.fullname }}
</p>
{% else %}
Guest
<p class="md-24">
<i class="material-icons md-48">face</i>
Guest
</p>
{% endif %}
</span>
<div class="mdl-layout-spacer"></div>
<button id="accbtn" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
<i class="material-icons" role="presentation">arrow_drop_down</i>
<span class="visuallyhidden">Account</span>
</button>
</span>
<ul class="mdl-menu mdl-menu--bottom-left mdl-js-menu mdl-js-ripple-effet" for="accbtn">
{% if current_user.is_authenticated() %}
<li class="mdl-menu__item"><a class="mdl-navigation__link" href="{{ url_for("logout") }}">Logout</a></li>
......@@ -56,13 +72,19 @@
</div>
</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>
{% 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>
{% 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 %}
</nav>
</div>
<main class="mdl-layout__content mdl-color--grey-100">
<div class="mdl-grid rede-content">
<div id="rede-content-div" class="mdl-grid rede-content">
{% block content %}
There is no content yet.
{% endblock %}
......
......@@ -10,10 +10,10 @@
{% macro render_stringfield(field) -%}
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input id="{{ field.id }}" name="{{ field.id }}" class="mdl-textfield__input" type="text" value="{{ field.data }}" />
<input id="{{ field.id }}" name="{{ field.id }}" class="mdl-textfield__input" type="text"{% if field.data is not none %}value="{{ field.data }}"{% endif %} />
<label class="mdl-textfield__label" for="{{ field.id }}">{{ field.label.text }}</label>
{% if field.errors %}
{% for e in errors %}
{% for e in field.errors %}
<div class="mdl-card__supporting-text">
{{ e }}
</div>
......@@ -27,7 +27,7 @@
<input id="{{ field.id }}" name="{{ field.id }}" class="mdl-textfield__input" type="password" />
<label class="mdl-textfield__label" for="{{ field.id }}">{{ field.label.text }}</label>
{% if field.errors %}
{% for e in errors %}
{% for e in field.errors %}
<div class="mdl-card__supporting-text">
{{ e }}
</div>
......@@ -42,7 +42,7 @@
<span class="mdl-checkbox__label">{{ field.label.text }}</span>
</label>
{% if field.errors %}
{% for e in errors %}
{% for e in field.errors %}
<div class="mdl-card__supporting-text">
{{ e }}
</div>
......@@ -65,7 +65,9 @@
</select>
{% if field.errors %}
{% for e in field.errors %}
<p class="help-block">{{ e }}</p>
<div class="mdl-card__supporting-text">
{{ e }}
</div>
{% endfor %}
{% endif %}
</label>
......@@ -73,11 +75,11 @@
{% macro render_form(form, action_url="", title=None, action_text="Submit", class_="mdl-card mdl-shadow--2dp", title_class="mdl-card__title", title_next_class="mdl-card__title-text", content_class="mdl-card__supporting-text", action_class="mdl-card__actions", btn_class="mdl-button mdl-js-button mdl-button--raised mdl-button-colored") -%}
{% macro render_form(form, action_url="", title=None, action_text="Submit", class_="mdl-card mdl-shadow--2dp mdl-cell mdl-cell--4-col mdl-cell--4-col-tablet mdl-cell--4-col-phone", title_class="mdl-card__title", title_next_class="mdl-card__title-text", content_class="mdl-card__supporting-text", action_class="mdl-card__actions", btn_class="mdl-button mdl-js-button mdl-button--raised mdl-button-colored") -%}
<div class="{{ class_ }}">
<form method="POST" action="{{ action_url }}">
<div class="{{ title_class }}">
<h2 class="{{ title_text_class}}">{{ title if title is not none else action_text }}</h2>
<h3 class="{{ title_text_class}}">{{ title if title is not none else action_text }}</h3>
</div>
<div class="{{ content_class }}">
{% for f in form %}
......
{% extends "layout.html" %}
{% from "macros.html" import render_form %}
{% block title %}Register{% endblock %}
{% block content %}
{{ render_form(form, action_url=url_for(".register", id=id), action_text="Add", title="Register") }}
{% endblock %}
{% extends "layout.html" %}
{% from "macros.html" import render_form %}
{% block title %}Statements{% endblock %}
{% block content %}
<table class="mdl-data-table mdl-js-table mdl-shadow--2dp mdl-cell mdl-cell--6-col mdl-cell--4-col-tablet mdl-cell--4-col-phone sortable">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">Speaker</th>
<th>Count</th>
{% 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>
{% endif %}
</tr>
</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>
<td>
<h5>{{ count }}</h5>
</td>
{% if "user" in current_user.roles %}
<td class="mdl-data-table__cell--non-numeric">
<a href="{{ url_for(".done", statement=statement.id) }}">
<button class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored">
<i class="material-icons">done</i>
</button>
</a>
</td>
<td class="mdl-data-table__cell--non-numeric">
<a href="{{ url_for(".cancel", statement=statement.id) }}">
<button class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab">
<i class="material-icons">delete</i>
</button>
</a>
</td>
{% endif %}
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% if current_user.is_authenticated() and "user" in current_user.roles %}
{{ render_form(add_form, action_url=url_for('.add', next=current), action_text="Add", title="Add Speaker") }}
{% endif %}
{% endblock %}
{% extends "layout.html" %}
{% from "macros.html" import render_form %}
{% block title %}Statements{% endblock %}
{% block additional_js %}
<script src="{{ url_for(".update_show_js", mode=mode) }}" async></script>
{% endblock %}
{% block content %}
<table class="mdl-data-table mdl-js-table mdl-shadow--2dp mdl-cell mdl-cell--12-col mdl-cell--8-col-tablet mdl-cell--4-col-phone">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">Speaker</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 %}
<tr>
<td class="mdl-data-table__cell--non-numeric">
{{ speaker.name }}
</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 %}
</tbody>
</table>
{% endblock %}
{% from "macros.html" import render_form %}
<table class="mdl-data-table mdl-js-table mdl-shadow--2dp mdl-cell mdl-cell--12-col mdl-cell--8-col-tablet mdl-cell--4-col-phone">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">Speaker</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 %}
<tr>
<td class="mdl-data-table__cell--non-numeric">
{{ speaker.name }}
</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 %}
</tbody>
</table>
var returned = true;
var last_content = "";
function request() {
if (!returned)
return;
returned = false;
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
returned = true;
update(xmlhttp.responseText);
}
};
var target = "{{ url_for('.update', mode=mode) }}";
xmlhttp.open("GET", target, true);
xmlhttp.send();
}
function update(data) {
if (data != last_content) {
document.getElementById("rede-content-div").innerHTML = data;
last_content = data;
}
}
window.onload=function() {
window.setInterval(request, 1000);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment