better log, barcode scanner support

This commit is contained in:
metamuffin 2024-10-30 22:00:15 +01:00
parent a7868afbcf
commit c3dadcc5a3
No known key found for this signature in database
GPG key ID: 718F9749DCDBD654

View file

@ -41,13 +41,22 @@ local stylesheet = [[
.amount-neg { color: red; } .amount-neg { color: red; }
nav h2 { display: inline-block } nav h2 { display: inline-block }
.notif { padding: 0.5em; margin: 0.5em; background-color: #ddd; } .notif { padding: 0.5em; margin: 0.5em; background-color: #ddd; }
.notif.error { background-color: #faa; }
.notif p { margin: 5px; } .notif p { margin: 5px; }
form.box { border: 2px solid grey; padding: 0.5em; margin: 0.5em; display: inline-block; } form.box { border: 2px solid grey; padding: 0.5em; margin: 0.5em; display: inline-block; }
form h3 { margin: 5px; } form h3 { margin: 5px; }
]] ]]
-- local script = io.open("main.js"):read("a")
local script = [[ 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) local function respond(status, title, body)
@ -55,6 +64,7 @@ local function respond(status, title, body)
print("Content-Type: text/html") print("Content-Type: text/html")
print("") print("")
print(string.format([[ print(string.format([[
<!DOCTYPE html>
<html><head> <html><head>
<title>%s</title> <title>%s</title>
<meta charset="utf-8" /> <meta charset="utf-8" />
@ -88,6 +98,13 @@ local function form_data()
return parse_query(io.read()) return parse_query(io.read())
end 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 function read_log()
local log = io.open("log", "r") local log = io.open("log", "r")
if log == nil then if log == nil then
@ -126,54 +143,65 @@ local function balances()
end end
return users return users
end end
local function last_txns()
local users = {}
for time, username, _, _ in read_log() do
users[username] = time
end
return users
end
local function r_user() local function error_box(message)
if path == nil then return string.format([[<div class="notif error"><p>Error: %s</p></div>]], message)
return respond_error("no path") end
end
local username = urldecode(path:sub(2)) local function r_user_post(username)
if username == nil or username:match("^([%w_ -]+)$") == nil then local data = form_data()
return respond_error("username invalid") local amount = nil
end local comment = ""
local notif = nil if data.product then
if method == "POST" then for p_barcode, p_amount, p_name in read_products() do
local data = form_data() if p_barcode == data.product then
local amount = nil amount = p_amount
local comment = "" comment = p_name
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
end end
else
amount = tonumber(data.amount)
comment = data.comment or ""
end end
if amount == nil then if amount == nil then
return respond_error("amount invalid") return error_box("unknown product")
end end
if comment:match("^[%w_ -]*$") == nil then else
return respond_error("comment invalid") amount = tonumber(data.amount)
end comment = data.comment or ""
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)
)
end 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() return respond(200, username, function()
print(string.format("<h1>%s</h1>", username)) print(string.format("<h1>%s</h1>", username))
local balance = balances()[username] local balance = balances()[username]
local last_txn = last_txns()[username]
local new_user = balance == nil local new_user = balance == nil
balance = balance or 0 balance = balance or 0
if new_user then 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> <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 end
if notif then if notif then print(notif) end
print(notif) print(string.format([[
end <p>Current balance: <span class="amount-%s">%.02f</p>
print(string.format("<p>Current balance: <span class=\"amount-%s\">%.02f€</p>", balance >= 0 and "pos" or "neg", ]], balance >= 0 and "pos" or "neg", balance / 100))
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([[ print([[
<form class="transaction box" action="" method="POST"> <form class="transaction box" action="" method="POST">
<h3>Create Transaction</h3> <h3>Create Transaction</h3>
@ -195,6 +225,12 @@ local function r_user()
<input type="text" name="comment" id="comment" /><br/> <input type="text" name="comment" id="comment" /><br/>
<input type="submit" value="Update" /> <input type="submit" value="Update" />
</form> </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\">") print("<div class=\"amount-presets\">")
for _, type in ipairs({ 1, -1 }) do for _, type in ipairs({ 1, -1 }) do
@ -214,14 +250,20 @@ local function r_user()
end) end)
end end
local function r_log() local function r_log(filter)
return respond(200, "Log", function() return respond(200, "Log", function()
print("<table>") print("<table>")
print("<tr><th>Time</th><th>Username</th><th>Amount</th><th>Comment</th></tr>") print("<tr><th>Time</th><th>Username</th><th>Amount</th><th>Comment</th></tr>")
for time, username, amount, comment in read_log() do 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, if filter == nil or filter == username then
escape(username), print(string.format(
amount >= 0 and "pos" or "neg", amount / 100, escape(comment))) "<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 end
print("</table>") print("</table>")
end) end)
@ -254,6 +296,17 @@ local function r_create_user()
return redirect(string.format("/%s", urlencode(username))) return redirect(string.format("/%s", urlencode(username)))
end 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 path == "/" then
if query.log then if query.log then
return r_log() return r_log()
@ -263,5 +316,12 @@ if path == "/" then
return r_index() return r_index()
end end
else 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 end