From cc4dee6ece87d554e7a5d81cc54be7d9df8e0b6e Mon Sep 17 00:00:00 2001 From: Michal Sojka Date: Tue, 18 Aug 2020 20:13:29 +0200 Subject: [PATCH 1/1] Add event logging MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This allows users to log various events such as coffee machine or milk container cleaning. Also, all users can see when was the last occurrence of the particular event. [Credits: This is a modified version of a patch from Jarda Klapálek.] --- app.py | 15 +++++++-- coffee_db.py | 21 +++++++++++++ templates/main.js | 23 +++++++++++++- templates/user.html | 76 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index 0e0564a..14a2684 100644 --- a/app.py +++ b/app.py @@ -115,11 +115,14 @@ def user(): 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') @@ -265,6 +268,14 @@ def coffee_add(): 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(): diff --git a/coffee_db.py b/coffee_db.py index 25551f9..bc53024 100644 --- a/coffee_db.py +++ b/coffee_db.py @@ -99,6 +99,15 @@ def add_coffee(uid, flavor, time=None): 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")) @@ -193,3 +202,15 @@ def drink_count(uid=None, start=None, stop=None): "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 diff --git a/templates/main.js b/templates/main.js index 417dc40..67e6db7 100644 --- a/templates/main.js +++ b/templates/main.js @@ -8,6 +8,7 @@ var logoutTimer; 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\"}"); @@ -46,9 +47,13 @@ function updateUI() 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 + "!"; } @@ -171,6 +176,7 @@ function logout() { id_user = undefined; timeToLogout = undefined; identifier_registration = false; + window.scrollTo(0, 0); // Scroll up } function countingTimeLogout(count_time) @@ -212,6 +218,21 @@ function addCoffee(flavor, time = new Date()) { } } + +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; diff --git a/templates/user.html b/templates/user.html index 5ad7b90..0a8597b 100644 --- a/templates/user.html +++ b/templates/user.html @@ -1,3 +1,36 @@ + + {% if name %}
@@ -5,6 +38,7 @@

Hello, {{ name }}!

+

{% if counts|length > 0 %} @@ -77,3 +111,45 @@ {% endif %} + +
+ + {%- macro event_box(title, events) -%} +
+

{{title | capitalize}}

+ {#- 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 %} +
+ + ({{ last_events[event] | humanize if event in last_events else "never" }}) +
+ {%- 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 %} +
+ {%- endmacro %} +
+

{{ ("Record
event" if name else "Events") | safe }}:

+ {{ 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'] ) }} +
+
-- 2.39.2