counts=counts,
identifiers=db.list_user_identifiers(uid),
iid=session["iid"],
- stamp=time.time()
+ stamp=time.time(),
+ last_events=db.last_events()
)
# TODO: Replace stamp parameter with proper cache control HTTP
# headers in response
- return render_template('user.html', stamp=time.time())
+ return render_template('user.html', stamp=time.time(),
+ last_events=db.last_events(),
+ )
@app.route('/user/rename')
return redirect(url_for('user'))
+@app.route("/event", methods=["POST"])
+def event_add():
+ json = request.json
+ print("User '%(uid)s' registered event %(event_name)s at %(time)s" % json)
+ db.add_event(json["uid"], json["event_name"], json["time"])
+ return redirect(url_for('user'))
+
+
# TODO: Remove me - unused
@app.route("/coffee/count")
def coffee_count():
c.execute("insert or ignore into coffees (id, flavor, time) values (?,?,?)", (uid, flavor, time))
close_db(conn)
+
+def add_event(uid, event_name, time):
+ conn, c = open_db()
+ c.execute("""insert into events (user_id, event_type, time)
+ values (?, (SELECT id FROM event_types WHERE name = ?), ?)""",
+ (uid, event_name, time))
+ close_db(conn)
+
+
def flavors():
conn, c = open_db()
res = list(c.execute("select distinct name, ord from flavors"))
"left join identifiers ids on co.id = ids.id where "
+ " and ".join(clauses) + " group by fl.type "
"order by fl.ord asc", args))
+
+
+def last_events():
+ """Return mapping with event names as keys and SQLite time string of
+ the last event as values.
+ """
+ conn, c = open_db()
+ res = dict(c.execute("""select name, MAX(time)
+ from events as e left join event_types as et on e.event_type = et.id
+ group by name"""))
+ close_db(conn)
+ return res
var reloadTimer = undefined;
var id_user; // ID of the user who is to be accounted for the next coffee
var identifier_registration = false; // true if identifier is supposed to be registered for user
+var eventMsg = undefined; // Feedback message about the last event performed by the user
console.log("hello from flask");
//sendJSON("{\"type\":\"empty\"}");
return;
}
+ if (eventMsg !== undefined) {
+ update("eventMsg", eventMsg);
+ eventMsg = undefined;
+ }
if (id_user !== undefined) {
document.getElementById("nextStep").innerHTML = "Now select a beverage on the coffee machine…";
- } else {
+ } else if (flavorChosen !== undefined) {
document.getElementById("nextStep").innerHTML = "Enjoy your " + flavorChosen + "!";
}
id_user = undefined;
timeToLogout = undefined;
identifier_registration = false;
+ window.scrollTo(0, 0); // Scroll up
}
function countingTimeLogout(count_time)
}
}
+
+function addEvent(event_name, action_msg, time = new Date()) {
+ var data = JSON.stringify({
+ time: time.toISOString(),
+ event_name: event_name,
+ uid: id_user
+ });
+ if (id_user) {
+ eventMsg = "You have " + action_msg + ". Thanks!"
+ ajax("POST", "event", data, "user");
+ window.scrollTo(0, 0); // Scroll up
+ }
+}
+
+
function addIdentifier_start() {
identifier_registration = true;
document.getElementById("addIdentifier").disabled = true;
+<style>
+.events {
+ margin: 0.8em;
+ margin-bottom: 1.5em;
+ padding: 2px;
+ border-spacing: 2em 0;
+}
+
+.events h3 {
+ display: inline-block;
+ margin-top: 1ex;
+ margin-right: 0.7em;
+}
+
+.events-box {
+ border: 1px solid black;
+ padding: 0.5em;
+ display: inline-block;
+ vertical-align: top;
+}
+
+.events-box h4 {
+ margin: 0.5ex;
+}
+.events-box .btnline {
+ text-align: left;
+}
+.events-box input {
+ padding: 1.5ex;
+ margin: 0.5ex;
+}
+</style>
+
{% if name %}
<form style="position: absolute; right: 15%; width: 15%; height: 15%;">
<button type="button" id="logout_button" onclick="logout()" style="width: 100%; height: 100%;">logout</button>
<h1>Hello, {{ name }}!</h1>
+ <p id="eventMsg"></p>
<p id="nextStep"></p>
{% if counts|length > 0 %}
<img src="{{ url_for('coffee_graph_history', _external=True, stamp=stamp) }}">
<img src="{{ url_for('coffee_graph_flavors', _external=True, stamp=stamp, days=7) }}">
{% endif %}
+
+ <br />
+ <form>
+ {%- macro event_box(title, events) -%}
+ <div class="events-box">
+ <h4>{{title | capitalize}}</h4>
+ {#- The first item in the list is used as button label, last item in the overview -#}
+ {%- set verb = {
+ "COFFEE_MACHINE_CLEANED": ["cleaned"],
+ "COFFEE_PACK_OPENED": ["opened"],
+ "LAST_COFFEE_PACK_OPENED": ["last opened"],
+ "MILK_CONTAINER_CLEANED": ["cleaned (water)", "cleaned"],
+ "MILK_CONTAINER_CLEANED_WITH_TABLET": ["cleaned (tablet)"],
+ }
+ -%}
+ {% if name -%} {# User logged in - show action buttons #}
+ {%- for event in events %}
+ <div class="btnline">
+ <input type="button" value="{{ verb[event]|first }}"
+ onclick="addEvent('{{ event }}', '{{ verb[events[0]]|last }} the {{ title }}')" />
+ ({{ last_events[event] | humanize if event in last_events else "never" }})
+ </div>
+ {%- endfor -%}
+ {%- else -%} {# Nobody logged in - show overview with summary times #}
+ {# Calculate maximum timestamp of all relevant events #}
+ {%- set when = last_events.items() | selectattr(0, 'in',
+ events) | map(attribute=1) | max | humanize -%}
+ {%- if when -%}
+ {{ verb[events[0]]|last }} {{ when }}
+ {%- else -%}
+ never {{ verb[events[0]]|last }}
+ {%- endif -%}
+ {%- endif %}
+ </div>
+ {%- endmacro %}
+ <div class="events">
+ <h3>{{ ("Record<br />event" if name else "Events") | safe }}:</h3>
+ {{ event_box('coffee machine', ['COFFEE_MACHINE_CLEANED'] ) }}
+ {{ event_box('coffee pack', ['COFFEE_PACK_OPENED'] ) }}
+ {{ event_box('milk container', ['MILK_CONTAINER_CLEANED', 'MILK_CONTAINER_CLEANED_WITH_TABLET'] ) }}
+ </div>
+ </form>