diff options
-rwxr-xr-x | strichliste.lua | 158 |
1 files changed, 109 insertions, 49 deletions
diff --git a/strichliste.lua b/strichliste.lua index 927a08a..4e941b9 100755 --- a/strichliste.lua +++ b/strichliste.lua @@ -41,13 +41,22 @@ local stylesheet = [[ .amount-neg { color: red; } nav h2 { display: inline-block } .notif { padding: 0.5em; margin: 0.5em; background-color: #ddd; } + .notif.error { background-color: #faa; } .notif p { margin: 5px; } form.box { border: 2px solid grey; padding: 0.5em; margin: 0.5em; display: inline-block; } form h3 { margin: 5px; } ]] +-- local script = io.open("main.js"):read("a") local script = [[ - + document.addEventListener("keypress", ev => { + if (!(document.activeElement instanceof HTMLInputElement)) { + if (ev.code.startsWith("Digit")) + document.forms.buy_product.product.value += ev.code.substring(5) + if (ev.code == "Enter") + document.forms.buy_product.submit() + } + }) ]] local function respond(status, title, body) @@ -55,6 +64,7 @@ local function respond(status, title, body) print("Content-Type: text/html") print("") print(string.format([[ + <!DOCTYPE html> <html><head> <title>%s</title> <meta charset="utf-8" /> @@ -88,6 +98,13 @@ local function form_data() return parse_query(io.read()) end +local function format_duration(t) + if t > 86400 then return string.format("%d days", t / 86400) end + if t > 3600 then return string.format("%d hours", t / 3600) end + if t > 60 then return string.format("%d minutes", t / 60) end + return string.format("%d seconds", t) +end + local function read_log() local log = io.open("log", "r") if log == nil then @@ -126,54 +143,65 @@ local function balances() end return users end - -local function r_user() - if path == nil then - return respond_error("no path") - end - local username = urldecode(path:sub(2)) - if username == nil or username:match("^([%w_ -]+)$") == nil then - return respond_error("username invalid") +local function last_txns() + local users = {} + for time, username, _, _ in read_log() do + users[username] = time end - local notif = nil - if method == "POST" then - local data = form_data() - local amount = nil - local comment = "" - if data.barcode then - for p_barcode, p_amount, p_name in read_products() do - if p_barcode == data.barcode then - amount = p_amount - comment = p_name - end + return users +end + +local function error_box(message) + return string.format([[<div class="notif error"><p>Error: %s</p></div>]], message) +end + +local function r_user_post(username) + local data = form_data() + local amount = nil + local comment = "" + if data.product then + for p_barcode, p_amount, p_name in read_products() do + if p_barcode == data.product then + amount = p_amount + comment = p_name end - else - amount = tonumber(data.amount) - comment = data.comment or "" end if amount == nil then - return respond_error("amount invalid") - end - if comment:match("^[%w_ -]*$") == nil then - return respond_error("comment invalid") + return error_box("unknown product") end - local log = io.open("log", "a+") - if log == nil then - return respond_error("failed to open log") - end - local time = os.time() - log:write(string.format("%d,%s,%d,%s\n", time, username, amount, comment)) - log:flush() - log:close() - notif = string.format( - "<div class=\"notif\"><p>Transaction successful: <strong class=\"amount-%s\">%.02f€</strong> (%s)</p></div>", - amount >= 0 and "pos" or "neg", amount / 100, escape(comment) - ) + else + amount = tonumber(data.amount) + comment = data.comment or "" end + if amount == nil then + return error_box("amount invalid") + end + if comment:match("^[%w_ -]*$") == nil then + return error_box("comment invalid") + end + local log = io.open("log", "a+") + if log == nil then + return error_box("failed to open log") + end + local time = os.time() + log:write(string.format("%d,%s,%d,%s\n", time, username, amount, comment)) + log:flush() + log:close() + return string.format( + "<div class=\"notif\"><p>Transaction successful: <strong class=\"amount-%s\">%.02f€</strong> (%s)</p></div>", + amount >= 0 and "pos" or "neg", amount / 100, escape(comment) + ) +end +local function r_user(username) + local notif = nil + if method == "POST" then + notif = r_user_post(username) + end return respond(200, username, function() print(string.format("<h1>%s</h1>", username)) local balance = balances()[username] + local last_txn = last_txns()[username] local new_user = balance == nil balance = balance or 0 if new_user then @@ -181,11 +209,13 @@ local function r_user() <div class="notif"><p><i>This user account does not exist yet. It will only be created after the first transaction.</i></p></div> ]]) end - if notif then - print(notif) - end - print(string.format("<p>Current balance: <span class=\"amount-%s\">%.02f€</p>", balance >= 0 and "pos" or "neg", - balance / 100)) + if notif then print(notif) end + print(string.format([[ + <p>Current balance: <span class="amount-%s">%.02f€</p> + ]], balance >= 0 and "pos" or "neg", balance / 100)) + print(string.format([[ + <p>Last transaction added %s ago. <a href="/%s?log">View user log</a> + ]], format_duration(os.time() - last_txn), username)) print([[ <form class="transaction box" action="" method="POST"> <h3>Create Transaction</h3> @@ -195,6 +225,12 @@ local function r_user() <input type="text" name="comment" id="comment" /><br/> <input type="submit" value="Update" /> </form> + <form class="transaction box" action="" method="POST" id="buy_product"> + <h3>Buy Product</h3> + <label for="product">Product: </label> + <input type="text" name="product" id="product" /><br/> + <input type="submit" value="Buy" /> + </form> ]]) print("<div class=\"amount-presets\">") for _, type in ipairs({ 1, -1 }) do @@ -214,14 +250,20 @@ local function r_user() end) end -local function r_log() +local function r_log(filter) return respond(200, "Log", function() print("<table>") print("<tr><th>Time</th><th>Username</th><th>Amount</th><th>Comment</th></tr>") for time, username, amount, comment in read_log() do - print(string.format("<tr><td>%d</td><td>%s</td><td class=\"amount-%s\">%.02f€</td><td>%s</td></tr>", time, - escape(username), - amount >= 0 and "pos" or "neg", amount / 100, escape(comment))) + if filter == nil or filter == username then + print(string.format( + "<tr><td>%d (%s ago)</td><td>%s</td><td class=\"amount-%s\">%.02f€</td><td>%s</td></tr>", + time, format_duration(os.time() - time), + escape(username), + amount >= 0 and "pos" or "neg", amount / 100, + escape(comment) + )) + end end print("</table>") end) @@ -254,6 +296,17 @@ local function r_create_user() return redirect(string.format("/%s", urlencode(username))) end +local function extract_username() + if path == nil then + return respond_error("no path") + end + local username = urldecode(path:sub(2)) + if username == nil or username:match("^([%w_ -]+)$") == nil then + return nil + end + return username +end + if path == "/" then if query.log then return r_log() @@ -263,5 +316,12 @@ if path == "/" then return r_index() end else - return r_user() + local username = extract_username() + if username == nil then + return respond_error("username invalid") + elseif query.log then + return r_log(username) + else + return r_user(username) + end end |