diff options
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | sql/tables.sql | 2 | ||||
-rw-r--r-- | src/audio/audio-interface.vala | 1 | ||||
-rw-r--r-- | src/audio/audio.vala | 4 | ||||
-rw-r--r-- | src/database/database.vala | 51 | ||||
-rw-r--r-- | src/database/db-interface.vala | 3 | ||||
-rw-r--r-- | src/scanner-session/scannersession.vala | 5 | ||||
-rw-r--r-- | src/web/Makefile | 2 | ||||
-rw-r--r-- | src/web/main.vala | 2 | ||||
-rw-r--r-- | src/web/web.vala | 27 | ||||
-rw-r--r-- | templates/css/base.css | 8 | ||||
-rw-r--r-- | templates/users/entry.html | 21 |
12 files changed, 108 insertions, 20 deletions
@@ -67,4 +67,6 @@ Usage: * setup ktt-shopsystem.cfg * start the curses UI in /etc/inittab * start the web UI via /etc/init.d/ + * create new user `TODO` + * Sets a user's password with `mdbus2 io.mainframe.shopsystem.Database /io/mainframe/shopsystem/database io.mainframe.shopsystem.Database.SetUserPassword 1 test` * call the invoice tool via cron diff --git a/sql/tables.sql b/sql/tables.sql index 0a6100f..a912740 100644 --- a/sql/tables.sql +++ b/sql/tables.sql @@ -3,7 +3,7 @@ CREATE TABLE IF NOT EXISTS products (id INTEGER PRIMARY KEY NOT NULL CHECK (id < CREATE TABLE IF NOT EXISTS sales (user INTEGER NOT NULL REFERENCES users, product INTEGER NOT NULL REFERENCES products, timestamp INTEGER NOT NULL DEFAULT 0); CREATE TABLE IF NOT EXISTS restock (user INTEGER NOT NULL REFERENCES users, product INTEGER NOT NULL REFERENCES products, amount INTEGER NOT NULL DEFAULT 0, timestamp INTEGER NOT NULL DEFAULT 0, price INTEGER NOT NULL DEFAULT 0, supplier INTEGER, best_before_date INTEGER); CREATE TABLE IF NOT EXISTS prices (product INTEGER NOT NULL REFERENCES products, valid_from INTEGER NOT NULL DEFAULT 0, memberprice INTEGER NOT NULL DEFAULT 0, guestprice INTEGER NOT NULL DEFAULT 0); -CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY NOT NULL, email TEXT, firstname TEXT NOT NULL, lastname TEXT NOT NULL, gender TEXT, street TEXT, plz INTEGER, city TEXT, pgp TEXT, disabled BOOLEAN NOT NULL DEFAULT 0, hidden BOOLEAN NOT NULL DEFAULT 0); +CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY NOT NULL, email TEXT, firstname TEXT NOT NULL, lastname TEXT NOT NULL, gender TEXT, street TEXT, plz INTEGER, city TEXT, pgp TEXT, disabled BOOLEAN NOT NULL DEFAULT 0, hidden BOOLEAN NOT NULL DEFAULT 0, sound_theme TEXT); CREATE TABLE IF NOT EXISTS authentication(user INTEGER PRIMARY KEY NOT NULL REFERENCES users, password TEXT, session CHARACTER(20), superuser BOOLEAN NOT NULL DEFAULT 0, auth_users BOOLEAN NOT NULL DEFAULT 0, auth_products BOOLEAN NOT NULL DEFAULT 0, auth_cashbox BOOLEAN NOT NULL DEFAULT 0, disabled BOOLEAN NOT NULL DEFAULT 0); CREATE TABLE IF NOT EXISTS supplier(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, city TEXT, postal_code TEXT, street TEXT, phone TEXT, website TEXT); CREATE TABLE IF NOT EXISTS cashbox_diff(id INTEGER PRIMARY KEY AUTOINCREMENT, user INTEGER NOT NULL REFERENCES users, amount INTEGER NOT NULL, timestamp INTEGER NOT NULL DEFAULT 0); diff --git a/src/audio/audio-interface.vala b/src/audio/audio-interface.vala index 89d4a6f..fe13af5 100644 --- a/src/audio/audio-interface.vala +++ b/src/audio/audio-interface.vala @@ -19,5 +19,6 @@ public interface AudioPlayer : Object { public abstract void play_system(string file) throws IOError; public abstract string get_random_user_theme() throws IOError; + public abstract string[] get_user_themes() throws IOError; public abstract void play_user(string theme, string type) throws IOError; } diff --git a/src/audio/audio.vala b/src/audio/audio.vala index a6e5007..1404969 100644 --- a/src/audio/audio.vala +++ b/src/audio/audio.vala @@ -74,6 +74,10 @@ public class AudioPlayerImplementation { return get_random_file(path + "user/"); } + public string[] get_user_themes() { + return get_files(path + "user/"); + } + public void play_user(string theme, string type) { p.set_state(Gst.State.NULL); var file = get_random_file(path + "user/" + theme+ "/" + type); diff --git a/src/database/database.vala b/src/database/database.vala index 74a554d..9596954 100644 --- a/src/database/database.vala +++ b/src/database/database.vala @@ -104,9 +104,11 @@ public class DataBase : Object { queries["session_set"] = "UPDATE authentication SET session=? WHERE user = ?"; queries["session_get"] = "SELECT user FROM authentication WHERE session = ?"; queries["username"] = "SELECT firstname, lastname FROM users WHERE id = ?"; + queries["user_theme_get"] = "SELECT CASE WHEN sound_theme IS NULL THEN ? ELSE sound_theme END FROM users WHERE id = ?"; + queries["user_theme_set"] = "UPDATE users SET sound_theme=? WHERE id = ?"; queries["password_get"] = "SELECT password FROM authentication WHERE user = ?"; queries["password_set"] = "UPDATE authentication SET password=? WHERE user = ?"; - queries["userinfo"] = "SELECT firstname, lastname, email, gender, street, plz, city, pgp, hidden, disabled FROM users WHERE id = ?"; + queries["userinfo"] = "SELECT firstname, lastname, email, gender, street, plz, city, pgp, hidden, disabled, sound_theme FROM users WHERE id = ?"; queries["userauth"] = "SELECT superuser, auth_users, auth_products, auth_cashbox FROM authentication WHERE user = ?"; queries["userauth_set"] = "UPDATE authentication SET auth_users = ?, auth_products = ?, auth_cashbox = ? WHERE user = ?"; queries["profit_by_product"] = "SELECT name, SUM(memberprice - (SELECT price FROM purchaseprices WHERE product = purch.product)) AS price FROM sales purch, prices, products WHERE purch.product = products.id AND purch.product = prices.product AND purch.user > 0 AND purch.timestamp > ? AND purch.timestamp < ? AND prices.valid_from = (SELECT valid_from FROM prices WHERE product = purch.product AND valid_from < purch.timestamp ORDER BY valid_from DESC LIMIT 1) GROUP BY name ORDER BY price;"; @@ -597,16 +599,17 @@ public class DataBase : Object { if(rc == Sqlite.ROW) { result.id = user; - result.firstname = statements["userinfo"].column_text(0); - result.lastname = statements["userinfo"].column_text(1); - result.email = statements["userinfo"].column_text(2); - result.gender = statements["userinfo"].column_text(3); - result.street = statements["userinfo"].column_text(4); - result.postcode = statements["userinfo"].column_text(5); - result.city = statements["userinfo"].column_text(6); - result.pgp = statements["userinfo"].column_text(7); - result.hidden = statements["userinfo"].column_int(8) == 1; - result.disabled = statements["userinfo"].column_int(9) == 1; + result.firstname = statements["userinfo"].column_text(0); + result.lastname = statements["userinfo"].column_text(1); + result.email = statements["userinfo"].column_text(2); + result.gender = statements["userinfo"].column_text(3); + result.street = statements["userinfo"].column_text(4); + result.postcode = statements["userinfo"].column_text(5); + result.city = statements["userinfo"].column_text(6); + result.pgp = statements["userinfo"].column_text(7); + result.hidden = statements["userinfo"].column_int(8) == 1; + result.disabled = statements["userinfo"].column_int(9) == 1; + result.soundTheme = statements["userinfo"].column_text(10); } else if(rc == Sqlite.DONE) { throw new DatabaseError.USER_NOT_FOUND("user not found"); } else { @@ -675,6 +678,32 @@ public class DataBase : Object { } } + public string get_user_theme(int user, string fallback) throws DatabaseError { + statements["user_theme_get"].reset(); + statements["user_theme_get"].bind_text(1, fallback); + statements["user_theme_get"].bind_int(2, user); + + if(statements["user_theme_get"].step() == Sqlite.ROW) { + return statements["user_theme_get"].column_text(0); + } else { + throw new DatabaseError.USER_NOT_FOUND("No such user available in database!"); + } + } + + public void set_userTheme(int user, string userTheme) throws DatabaseError { + statements["user_theme_set"].reset(); + if (userTheme == "") { + statements["user_theme_set"].bind_null(1); + } else { + statements["user_theme_set"].bind_text(1, userTheme); + } + statements["user_theme_set"].bind_int(2, user); + + int rc = statements["user_theme_set"].step(); + if(rc != Sqlite.DONE) + throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc); + } + public InvoiceEntry[] get_invoice(int user, int64 from=0, int64 to=-1) throws DatabaseError { InvoiceEntry[] result = {}; diff --git a/src/database/db-interface.vala b/src/database/db-interface.vala index f5bfada..6142fcf 100644 --- a/src/database/db-interface.vala +++ b/src/database/db-interface.vala @@ -32,11 +32,13 @@ public interface Database : Object { public abstract bool check_user_password(int32 user, string password) throws IOError; public abstract void set_user_password(int32 user, string password) throws IOError, DatabaseError; public abstract void set_sessionid(int user, string sessionid) throws IOError, DatabaseError; + public abstract void set_userTheme(int user, string userTheme) throws IOError, DatabaseError; public abstract int get_user_by_sessionid(string sessionid) throws IOError, DatabaseError; public abstract UserInfo get_user_info(int user) throws IOError, DatabaseError; public abstract UserAuth get_user_auth(int user) throws IOError, DatabaseError; public abstract void set_user_auth(UserAuth auth) throws IOError, DatabaseError; public abstract string get_username(int user) throws IOError, DatabaseError; + public abstract string get_user_theme(int user, string fallback) throws IOError, DatabaseError; public abstract InvoiceEntry[] get_invoice(int user, int64 from=0, int64 to=-1) throws IOError, DatabaseError; public abstract int64 get_first_purchase(int user) throws IOError; public abstract int64 get_last_purchase(int user) throws IOError; @@ -121,6 +123,7 @@ public struct UserInfo { public string pgp; public bool disabled; public bool hidden; + public string soundTheme; public bool equals(UserInfo x) { if(id != x.id) return false; diff --git a/src/scanner-session/scannersession.vala b/src/scanner-session/scannersession.vala index 27213c2..cbce9d3 100644 --- a/src/scanner-session/scannersession.vala +++ b/src/scanner-session/scannersession.vala @@ -67,7 +67,10 @@ public class ScannerSessionImplementation { this.logged_in = true; try { - this.theme = audio.get_random_user_theme(); + this.theme = db.get_user_theme(user, ""); + if (this.theme == "") { + this.theme = audio.get_random_user_theme(); + } } catch(IOError e) { this.theme = "beep"; } diff --git a/src/web/Makefile b/src/web/Makefile index 17140c3..e6094f6 100644 --- a/src/web/Makefile +++ b/src/web/Makefile @@ -1,7 +1,7 @@ all: web @echo > /dev/null -web: main.vala web.vala websession.vala csv.vala template.vala ../database/db-interface.vala ../pgp/pgp-interface.vala ../price.vapi ../config/config-interface.vala +web: main.vala web.vala websession.vala csv.vala template.vala ../database/db-interface.vala ../pgp/pgp-interface.vala ../price.vapi ../config/config-interface.vala ../audio/audio-interface.vala valac -X -w -o $@ --vapidir=../../vapi --enable-experimental --pkg gee-0.8 --pkg gio-2.0 --pkg libsoup-2.4 --pkg posix $^ clean: diff --git a/src/web/main.vala b/src/web/main.vala index c0fd77f..7070e66 100644 --- a/src/web/main.vala +++ b/src/web/main.vala @@ -17,6 +17,7 @@ Database db; public CSVMemberFile csvimport; public PGP pgp; public Config cfg; +public AudioPlayer audio; string templatedir; public static int main(string[] args) { @@ -29,6 +30,7 @@ public static int main(string[] args) { db = Bus.get_proxy_sync(BusType.SYSTEM, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database"); pgp = Bus.get_proxy_sync(BusType.SYSTEM, "io.mainframe.shopsystem.PGP", "/io/mainframe/shopsystem/pgp"); cfg = Bus.get_proxy_sync(BusType.SYSTEM, "io.mainframe.shopsystem.Config", "/io/mainframe/shopsystem/config"); + audio = Bus.get_proxy_sync(BusType.SYSTEM, "io.mainframe.shopsystem.AudioPlayer", "/io/mainframe/shopsystem/audio"); templatedir = cfg.get_string("WEB", "filepath"); port = cfg.get_integer("WEB", "port"); diff --git a/src/web/web.vala b/src/web/web.vala index fb03e4b..c63db73 100644 --- a/src/web/web.vala +++ b/src/web/web.vala @@ -359,19 +359,36 @@ public class WebServer { t.replace("ISADMIN2", "disabled=\"disabled\""); } + var userThemeList = audio.get_user_themes(); + var message = ""; var postdata = Soup.Form.decode_multipart(msg, null, null, null, null); if(postdata != null && postdata.contains("password1") && postdata.contains("password2")) { if(postdata["password1"] != postdata["password2"]) { - t.replace("MESSAGE", "<div class=\"alert alert-error\">Error! Passwords do not match!</div>"); + message = "<div class=\"alert alert-error\">Error! Passwords do not match!</div>"; } else if(postdata["password1"] == "") { - t.replace("MESSAGE", "<div class=\"alert alert-error\">Error! Empty Password not allowed!</div>"); + message = "<div class=\"alert alert-error\">Error! Empty Password not allowed!</div>"; } else { db.set_user_password(id, postdata["password1"]); - t.replace("MESSAGE", "<div class=\"alert alert-success\">Password Changed!</div>"); + message = "<div class=\"alert alert-success\">Password Changed!</div>"; } - } else { - t.replace("MESSAGE", ""); + } else if(postdata != null && postdata.contains("soundTheme")) { + if (postdata["soundTheme"] in userThemeList) { + userinfo.soundTheme = postdata["soundTheme"]; + db.set_userTheme(id, postdata["soundTheme"]); + } else { + userinfo.soundTheme = null; + db.set_userTheme(id, ""); + } + message = "<div class=\"alert alert-success\">Sound theme changed.</div>"; + } + t.replace("MESSAGE", message); + + var soundThemes = ""; + foreach(var theme in userThemeList) { + var selected = userinfo.soundTheme == theme ? "selected" : ""; + soundThemes += @"<option $selected>$theme</option>"; } + t.replace("SOUND_THEMES", soundThemes); msg.set_response("text/html", Soup.MemoryUse.COPY, t.data); msg.set_status(200); diff --git a/templates/css/base.css b/templates/css/base.css index 6192406..e273808 100644 --- a/templates/css/base.css +++ b/templates/css/base.css @@ -76,6 +76,14 @@ text-align: right !important; } +table.user-entry th { + min-width: 150px; +} + +table.user-entry td { + min-width: 350px; +} + @media print { .navbar-fixed-top { display: none !important; diff --git a/templates/users/entry.html b/templates/users/entry.html index d72b304..60d2dd3 100644 --- a/templates/users/entry.html +++ b/templates/users/entry.html @@ -3,7 +3,7 @@ {{{MESSAGE}}} <form method="POST" enctype="multipart/form-data" action="#"> - <table class="table table-bordered table-nonfluid"> + <table class="table table-bordered table-nonfluid user-entry"> <tr><th>ID</th><td>{{{UID}}}</td></tr> <tr> <th>Barcode</th> @@ -22,6 +22,24 @@ <tr><th>Street</th><td>{{{STREET}}}</td></tr> <tr><th>PLZ</th><td>{{{POSTALCODE}}}</td></tr> <tr><th>City</th><td>{{{CITY}}}</td></tr> + <tr><th colspan="2">Settings</th></tr> + <tr><th>Sound theme</th> + <td> + <form method="POST" enctype="multipart/form-data" action="#"> + <select class="form-control" name="soundTheme"> + <option value="##random">~ random ~</option> + {{{SOUND_THEMES}}} + </select> + <input type="submit" class="btn btn-default" value="Update"> + </form> + <br> + <a href="https://github.com/ktt-ol/serial-barcode-scanner/tree/master/sounds/user" target="_blank">See Preview</a> + </td> + </tr> + </table> +</form> +<form method="POST" enctype="multipart/form-data" action="#"> + <table class="table table-bordered table-nonfluid user-entry"> <tr><th colspan="2">Status Information</th></tr> <tr><th>Disabled</th><td>{{{DISABLED}}}</td></tr> <tr><th>Hidden</th><td>{{{HIDDEN}}}</td></tr> @@ -41,6 +59,7 @@ code39_init(); code39_draw("USER {{{UID}}}", true); + $('#authproductsbutton').on('click', function (e) { var req = $.getJSON( "/users/{{{UID}}}/toggle_auth_products", |