
Ahoj Jardo, už jsem myslel, že v patchi bude jen pár kosmetických nedostatků, které snadno opravím, ale ještě tam je pár zásadních problémů. Nejpodstatnější je asi mazání id. Viz níže. -M. On Fri, Mar 22 2019, Jaroslav Klapalek wrote:
Users can register multiple identifiers for a single account. Also they can rename identifiers (each identifier has its own name) and unregister/remove them from the account.
[...]
Possible TODOs: - add option to merge two identifiers (e. g. if one is lost, it should be possible to transfer all coffees to different one), - divide identifiers to 2+ groups -- 'master key' and 'regular', so the public ones (e. g. mugs) cannot remove identifiers from an account. Using e.g. "`status` INTEGER NOT NULL DEFAULT 0". --- Změny oproti v3: - nahrazení změny funkce updateRemote za proměnnou - odebrání sloupce 'status' app.py | 54 +++++++++++++++++++++++++++++++++++++------- coffee_db.py | 42 ++++++++++++++++++++++++++++++----- coffee_db.sql | 7 ++++++ templates/main.js | 64 ++++++++++++++++++++++++++++++++++++++++++++++------- templates/user.html | 21 ++++++++++++++++++ 5 files changed, 166 insertions(+), 22 deletions(-)
diff --git a/app.py b/app.py index 62f79b8..c5309b9 100644 --- a/app.py +++ b/app.py @@ -31,19 +31,28 @@ def hello():
@app.route('/login', methods=["POST"]) -@app.route('/login/<uid>') -def login(uid=None): +@app.route('/login/<iid>') +def login(iid=None): if request.method == "POST": - uid = request.data.decode("utf-8") - if uid is not None: - db.add_user(uid) - session["uid"] = uid + iid = request.data.decode("utf-8") + if iid is not None: + uid = db.get_uid(iid) + + db.add_user_identifier(iid, iid, "Default") + session["iid"] = iid + + if uid is None: + session["uid"] = iid + db.add_user(iid) + else: + session["uid"] = uid return redirect(url_for('user'))
@app.route('/logout') def logout(): session.pop('uid', None) + session.pop('iid', None) return redirect(url_for('user'))
@@ -55,6 +64,8 @@ def user(): name=db.get_name(uid), flavors=[_name for (_name, _ord) in db.flavors()], count=db.coffee_count(uid, 0), + identifiers=db.list_user_identifiers(uid), + iid=session["iid"], stamp=time.time() ) # TODO: Replace stamp parameter with proper cache control HTTP @@ -71,6 +82,31 @@ def user_rename(): return redirect(url_for('user'))
+@app.route('/user/identifier/add', methods=["POST"]) +def user_add_identifier(): + if request.method == "POST": + json = request.json + db.add_user_identifier(session["uid"], json["id"], 'None') + return redirect(url_for('user')) + + +@app.route('/user/identifier/rename', methods=["POST"]) +def user_rename_identifier(): + if request.method == "POST": + json = request.json + db.rename_user_identifier(session["uid"], json["id"], json["name"]) + return redirect(url_for('user')) + + +@app.route('/user/identifier/remove', methods=["POST"]) +def user_remove_identifier(): + if request.method == "POST": + json = request.json + db.remove_user_identifier(session["uid"], json["id"]) + return logout() # force logout + #return redirect(url_for('user')) + + @app.route("/coffee/graph_flavors") def coffee_graph_flavors(): days = request.args.get('days', default = 0, type = int) @@ -164,8 +200,10 @@ def coffee_graph_history(): def coffee_add(): if request.method == "POST": json = request.json - print("User '%(uid)s' had '%(flavor)s' at %(time)s" % json) - db.add_coffee(json["uid"], json["flavor"], json["time"]) + # Check if identifier is valid for current user + if json["iid"] in [i[1] for i in db.list_user_identifiers(db.get_uid(json["iid"]))]:
Tohle nedává moc smysl. Použiješ iid k získání všech id uživatele a zkontroluješ, jestli je mezi nimi to stejné iid je? Asi jsi chtěl hledat podle uid. Může tahle podmínka být někdy false? Myslím, že ne. A kdyby náhodou ano, uživateli se nezobrazí žádná chyba, jedině by si mohl všimnout, že se mu kafe neobjevilo na grafu. A pokud to má být obrana proti "útočníkům", tak to také nepomůže, protože když útočník bude umět podvrhnout iid v /coffee/add, bude si ho moct podvrhnout i v /user/identifier/add. Nebo mi něco uniká?
+ print("User '%(iid)s' had '%(flavor)s' at %(time)s" % json) + db.add_coffee(json["iid"], json["flavor"], json["time"]) return redirect(url_for('user'))
diff --git a/coffee_db.py b/coffee_db.py index 348113a..04c9c38 100644 --- a/coffee_db.py +++ b/coffee_db.py @@ -25,6 +25,11 @@ def add_user(uid): c.execute("insert or ignore into users (id) values (?)", (uid,)) close_db(conn)
+def add_user_identifier(uid, iid, name): + conn, c = open_db() + c.execute("insert or ignore into identifiers (userid, id, name) values (?, ?, ?)", (uid, iid, name, )) + close_db(conn) + def get_name(uid): conn, c = open_db() for name, in c.execute("select name from users where id = ?",(uid,)): @@ -33,18 +38,43 @@ def get_name(uid): close_db(conn) return None
+def get_uid(iid): + conn, c = open_db() + res = list(c.execute(""" + select userid from identifiers where id = ? + """, (iid,))) + + return res[0][0] if len(res) > 0 else None
def name_user(uid, name): conn, c = open_db() c.execute("update users set name = ? where id = ?", (name, uid)) close_db(conn)
+def rename_user_identifier(uid, iid, name): + conn, c = open_db() + c.execute("update identifiers set name = ? where userid = ? and id = ?", (name, uid, iid, )) + close_db(conn) + +def remove_user_identifier(uid, iid): + conn, c = open_db() + c.execute("delete from identifiers where userid = ? and id = ?", (uid, iid, ))
Kdo bude platit všechna moje kafe, když si smažu identifikátor (iid), na který jsou registrována? Buďto to chce kafe připisovat jako do teď na uid, která nejdou smazat (převod z iid na uid by se dělal až na serveru) a nebo je potřeba do tabulky identifikátorů přidat flag "valid" a mazání iid záznam nesmaže, ale jen zruší valid. Pokud pak iid zaregistruji k jinému uid, valid se zase obnoví. Neřešil to ten status, který jsi ve v4 odebral?
+ close_db(conn) + def list_users(): conn, c = open_db() for row in c.execute("select * from users"): print(row) close_db(conn)
+def list_user_identifiers(uid): + conn, c = open_db() + res = list(c.execute(""" + select * from identifiers where userid = ? + """, (uid,))) + close_db(conn) + return res +
def add_coffee(uid, flavor, time=None): conn, c = open_db() @@ -80,15 +110,15 @@ def coffee_flavors(uid=None, days=0, start=0): query += " where date(time) between date('now', 'localtime', '-"+ str(days+start-1) +" days') and date('now', 'localtime', '-"+ str(start) +" days')"
if uid is not None: - query += " and id = ?" + query += " and ids.userid = ?" variables.append(uid) elif uid is not None: - query += " where id = ?" + query += " where ids.userid = ?" variables.append(uid)
res = list(c.execute(""" select f.name, count(c.flavor) from flavors f - left join (select * from coffees + left join (select * from coffees co left join identifiers ids on co.id=ids.id """+query+""") c on f.name=c.flavor group by f.name order by f.ord asc @@ -114,7 +144,7 @@ def coffee_history(uid=None): select strftime('%s', ds.d),count(c.flavor),c.flavor from (select num,date('now', 'localtime', -num || ' days') as d from days) ds left join - (select date(time, 'localtime') as time,flavor from coffees where id = ?) c + (select date(time, 'localtime') as time,flavor from coffees co left join identifiers ids on co.id = ids.id where ids.userid = ?) c on d = date(c.time) group by d, c.flavor """ , (uid,))) @@ -129,7 +159,7 @@ def coffee_count(uid=None, start=None, stop=None): clauses = []
if uid is not None: - clauses.append("id = ?") + clauses.append("ids.userid = ?") args.append(uid)
if start is not None: @@ -139,7 +169,7 @@ def coffee_count(uid=None, start=None, stop=None): clauses.append("date(time, 'localtime') <= date('now', 'localtime', '-%d days')" % int(stop))
for count, in c.execute( - "select count(*) from coffees where " + + "select count(*) from coffees co left join identifiers ids on co.id = ids.id where " + " and ".join(clauses) , args): res = count diff --git a/coffee_db.sql b/coffee_db.sql index acb42a2..5d86ee9 100644 --- a/coffee_db.sql +++ b/coffee_db.sql @@ -35,3 +35,10 @@ create table if not exists days ( insert or ignore into days values (0),(1),(2),(3),(4),(5),(6) ; + +CREATE TABLE if not exists identifiers ( + `userid` varchar ( 24 ) NOT NULL, + `id` varchar ( 24 ) NOT NULL UNIQUE, + `name` varchar ( 24 ), + FOREIGN KEY(`userid`) REFERENCES `users`(`id`) +); diff --git a/templates/main.js b/templates/main.js index b28b826..5bb8bb4 100644 --- a/templates/main.js +++ b/templates/main.js @@ -2,11 +2,12 @@ var flask = "{{ url_for('hello', _external=True) }}"
// State variables
-var updateRemote = undefined; // defined iff remote server accessible -var timeToLogout = undefined; // defined during logout countdown +var updateRemote = undefined; // defined iff remote server accessible +var timeToLogout = undefined; // defined during logout countdown var logoutTimer; var reloadTimer = undefined; -var id_user; // ID of the user who is to be accounted for the next coffee +var id_user; // ID of the user who is to be accounted for the next coffee +var identifier_registration = false; // true if 'use ident
Ten komentář je nějaký useknutý, ne?
console.log("hello from flask"); //sendJSON("{\"type\":\"empty\"}"); @@ -62,22 +63,34 @@ function updateUI() function hiddenUpdateRemote(json, time = new Date()) { var msg = JSON.parse(json);
+ var data = JSON.stringify({
Data se používá jen v case 'rfid', tak to nadefinuj až tam.
+ id: msg.uid, + uid: id_user
Server uid nepoužívá - bere ho z session.
+ }); + switch(msg.type) { case "empty": break; case "rfid": - login(msg.uid); + (identifier_registration ? ajax("POST", "user/identifier/add", data, "user") : login(msg.uid)); break; case "keys": - var flavor = getFlavor(msg.key); - if (flavor !== "") { - addCoffee(flavor, time); + if (!identifier_registration) { + var flavor = getFlavor(msg.key); + if (flavor !== "") { + addCoffee(flavor, time); + }
Myslím, že tohle není třeba vůbec měnit. Kafe to může počítat i když jsi v módu přidávání.
} break; case "ajax_failure": ajax(msg.method, msg.route, msg.data, msg.id); break; } + + if (identifier_registration) { + addIdentifier_finish(); + }
A tohle bych dal taky do case 'rfid'. Když by ti za tvými zády někdo stiskl při přidávání id nějaké tlačítko na kávovaru, nové id by se ti nepřidalo.
+ sendLog(json); }
@@ -160,6 +173,8 @@ function logout() { ajax("GET", "logout", "", "user"); id_user = undefined; timeToLogout = undefined; + updateRemote = hiddenUpdateRemote;
Tohle teď není potřeba.
+ identifier_registration = false; }
function countingTimeLogout(count_time) @@ -192,7 +207,7 @@ function addCoffee(flavor, time = new Date()) { var data = JSON.stringify({ time: time.toISOString(), flavor: flavor, - uid: id_user + iid: id_user }); if (id_user) { ajax("POST", "coffee/add", data, "user"); @@ -202,6 +217,39 @@ function addCoffee(flavor, time = new Date()) { } }
+function addIdentifier_start() { + identifier_registration = true; + document.getElementById("addIdentifier").disabled = true; + document.getElementById("labelIdentifier").style.visibility = "visible"; + document.getElementById("abortIdentifier").disabled = false; +} + +function addIdentifier_finish() { + identifier_registration = false; + document.getElementById("addIdentifier").disabled = false; + document.getElementById("labelIdentifier").style.visibility = "hidden"; + document.getElementById("abortIdentifier").disabled = true; +} + +function renameIdentifier(i) { + var data = JSON.stringify({ + id: document.getElementById("identifier_" + i).innerText, + uid: id_user,
UID se bere z session, takže se tu nemusí posílat.
+ name: document.getElementById("identifier_name_" + i).value + }); + + ajax("POST", "user/identifier/rename", data, "user"); +} + +function removeIdentifier(id) { + var data = JSON.stringify({ + id: id, + uid: id_user
Také se nepoužívá.
+ }); + + ajax("POST", "user/identifier/remove", data, "user"); +} + function sendLog(json) { ajax("POST", "log", json, "log"); } diff --git a/templates/user.html b/templates/user.html index 7e549b9..8577d15 100644 --- a/templates/user.html +++ b/templates/user.html @@ -25,10 +25,31 @@ </p> <p> <form> + <label for="username">Username:</label> <input id="username" type="text" name="name"> <input type="button" value="rename" onclick="renameUser()"> </form> </p> + <form> + <table style="padding: 2px"> + <tr> + <td colspan="4" align="center"><b>Identifiers:</b></td> + </tr> + {% for id in identifiers %} + <tr> + <td><input type="text" id="identifier_name_{{ loop.index }}" value="{{ id[2] }}" /></td> + <td {% if iid == id[1] %} style="font-weight: bold" {% endif %}>#<span id="identifier_{{ loop.index }}">{{ id[1] }}</span></td> + <td><input type="button" value="rename" onclick="renameIdentifier({{ loop.index }})" /></td> + <td><input type="button" value="remove" onclick="removeIdentifier({{ id[1] }})" /></td> + </tr> + {% endfor %} + <tr> + <td><input type="button" id="addIdentifier" value="add identifier" onclick="addIdentifier_start()" /></td> + <td colspan="2" style="visibility: hidden" id="labelIdentifier"><b>Use your identifier.</b></td> + <td><input type="button" id="abortIdentifier" value="abort" disabled onclick="addIdentifier_finish()" /></td> + </tr> + </table> + </form> {% else %} <p>Use your card/token to log in...</p>
-- 2.7.4
_______________________________________________ Coffee mailing list Coffee@rtime.felk.cvut.cz https://rtime.felk.cvut.cz/mailman/listinfo/coffee