]> rtime.felk.cvut.cz Git - coffee/coffee-flask.git/commitdiff
Add event logging
authorMichal Sojka <michal.sojka@cvut.cz>
Tue, 18 Aug 2020 18:13:29 +0000 (20:13 +0200)
committerMichal Sojka <michal.sojka@cvut.cz>
Wed, 19 Aug 2020 22:27:02 +0000 (00:27 +0200)
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
coffee_db.py
templates/main.js
templates/user.html

diff --git a/app.py b/app.py
index 0e0564aa398d4ad8fc256edf80852914b6ad097e..14a26842d4faccf78c975f5e327bb3485f21f565 100644 (file)
--- 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():
index 25551f90fed08e2a54dd1ef53f62c50fabbd2f99..bc53024f4bc90a8b0377923b5720b9b93b910b6d 100644 (file)
@@ -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
index 417dc40f8d88edee6ad278ec6a0bd31590916361..67e6db740c4eb326893db5dba72d2434b80daed7 100644 (file)
@@ -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;
index 5ad7b901584c6fa01eab306c41af6fc878197bc6..0a8597bd70a2f100889caabeba985ca8a4751427 100644 (file)
@@ -1,3 +1,36 @@
+<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>
@@ -5,6 +38,7 @@
 
     <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>