refactor things

This commit is contained in:
metamuffin 2024-10-30 13:50:36 +01:00
parent 435c2a78f9
commit 498cbfe9c8
No known key found for this signature in database
GPG key ID: 718F9749DCDBD654

View file

@ -1,12 +1,52 @@
#!/usr/bin/env luajit #!/usr/bin/env luajit
local path = os.getenv("PATH_INFO")
local method = os.getenv("REQUEST_METHOD")
local query = os.getenv("QUERY_STRING")
local function escape(s) local function escape(s)
return s:gsub("<", "&lt;"):gsub("<", "&lt;") return s:gsub("<", "&lt;"):gsub("<", "&lt;")
end end
local function urldecode(s)
if s == nil then return nil end
return s:gsub("+", " "):gsub("%%20", " ")
end
local function urlencode(s)
if s == nil then return nil end
return s:gsub(" ", "%%20")
end
local function parse_query(q)
if q == nil then return {} end
local data = {}
for pair in string.gmatch(q, "([^&]+)") do
local flag = string.match(pair, "^([^=]+)$")
if flag ~= nil then
data[flag] = "1"
else
local key, value = string.match(pair, "^([^=]+)=([^=]*)$")
if key ~= nil and value ~= nil then
data[key] = urldecode(value)
end
end
end
return data
end
local path = os.getenv("PATH_INFO")
local method = os.getenv("REQUEST_METHOD")
local query = parse_query(os.getenv("QUERY_STRING"))
local stylesheet = [[
/* body { background-color: #161616; }
h1, h2, h3, h4, h5, h6, p, label, a { color: #e2e2e2; } */
.amount-presets form { display: inline-block; width: 60px }
.amount-pos { color: green; }
.amount-neg { color: red; }
nav h2 { display: inline-block }
.notif { padding: 0.5em; margin: 0.5em; background-color: #ddd; }
.notif p { margin: 5px }
]]
local script = [[
]]
local function respond(status, title, body) local function respond(status, title, body)
print(string.format("Status: %d", status)) print(string.format("Status: %d", status))
@ -16,8 +56,16 @@ local function respond(status, title, body)
<html><head> <html><head>
<title>%s</title> <title>%s</title>
<meta charset="utf-8" /> <meta charset="utf-8" />
</head><body> <style>%s</style>
]], escape(title))) <script>%s</script>
</head>
<body>
<nav>
<h2><a href="/">Strichliste v2</a></h2>
<span><a href="/?log">View Log</a></span>
<span><a href="https://codeberg.org/metamuffin/strichliste">Source</a></span>
</nav>
]], escape(title), stylesheet, script))
body() body()
print("</body></html>") print("</body></html>")
end end
@ -35,16 +83,7 @@ local function redirect(path)
end end
local function form_data() local function form_data()
local data = {} return parse_query(io.read())
for pair in string.gmatch(io.read(), "([^&]+)") do
local key, value = string.match(pair, "([^=]+)=([^=]+)")
if key == nil or value == nil then
goto continue
end
data[key] = value
::continue::
end
return data
end end
local function read_log() local function read_log()
@ -55,10 +94,28 @@ local function read_log()
local lines = log:lines("l") local lines = log:lines("l")
return function() return function()
local l = lines() local l = lines()
local time, username, amount, comment = string.match(l, "(%d+),([%w_-]+),(-?%d+),([%w_-]*)") if l == "" or l == nil then
return nil
end
local time, username, amount, comment = string.match(l, "(%d+),([%w_ -]+),(-?%d+),([%w_ -]*)")
return tonumber(time), username, tonumber(amount), comment return tonumber(time), username, tonumber(amount), comment
end end
end end
local function read_products()
local log = io.open("products", "r")
if log == nil then
return function() return nil end
end
local lines = log:lines("l")
return function()
local l = lines()
if l == "" or l == nil then
return nil
end
local barcode, amount, name = string.match(l, "([%w_-]+),(-?%d+),([%w_ -]*)")
return barcode, tonumber(amount), name
end
end
local function balances() local function balances()
local users = {} local users = {}
@ -72,19 +129,30 @@ local function r_user()
if path == nil then if path == nil then
return respond_error("no path") return respond_error("no path")
end end
local username = path:sub(2) local username = urldecode(path:sub(2))
if username:match("^[%w_-]+$") == nil then if username == nil or username:match("^([%w_ -]+)$") == nil then
return respond_error("username invalid") return respond_error("username invalid")
end end
local notif = nil
if method == "POST" then if method == "POST" then
local data = form_data() local data = form_data()
local amount = tonumber(data.amount) 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
end
else
amount = tonumber(data.amount)
comment = data.comment or ""
end
if amount == nil then if amount == nil then
return respond_error("amount invalid") return respond_error("amount invalid")
end end
local comment = data.comment or "" if comment:match("^[%w_ -]*$") == nil then
if comment:match("^[%w_-]*$") == nil then
return respond_error("comment invalid") return respond_error("comment invalid")
end end
local log = io.open("log", "a+") local log = io.open("log", "a+")
@ -95,14 +163,29 @@ local function r_user()
log:write(string.format("%d,%s,%s,%s\n", time, username, amount, comment)) log:write(string.format("%d,%s,%s,%s\n", time, username, amount, comment))
log:flush() log:flush()
log:close() 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
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] or 0 local balance = balances()[username]
print(string.format("Current balance: %.02f", balance / 100)) local new_user = balance == nil
balance = balance or 0
if new_user then
print([[
<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))
print([[ print([[
<form action="" method="POST"> <form class="transaction" action="" method="POST">
<label for="amount">Amount: </label> <label for="amount">Amount: </label>
<input type="number" name="amount" id="amount" /><br/> <input type="number" name="amount" id="amount" /><br/>
<label for="comment">Comment: </label> <label for="comment">Comment: </label>
@ -110,17 +193,21 @@ local function r_user()
<input type="submit" value="Update" /> <input type="submit" value="Update" />
</form> </form>
]]) ]])
print("<div class=\"amount-presets\">")
for _, type in ipairs({ 1, -1 }) do for _, type in ipairs({ 1, -1 }) do
for _, amount in ipairs({ 50, 100, 150, 200, 500, 1000 }) do for _, amount in ipairs({ 50, 100, 150, 200, 500, 1000 }) do
print(string.format([[ print(string.format([[
<form action="" method="POST"> <form action="" method="POST">
<input type="number" name="amount" id="amount" value="%d" hidden /> <input type="number" name="amount" id="amount" value="%d" hidden />
<input type="text" name="comment" id="comment" value="" hidden /> <input type="text" name="comment" id="comment" value="" hidden />
<input type="submit" value="%s%.02f€" /> <input type="submit" value="%s%.02f€" class="amount-%s" />
</form> </form>
]], amount * type, ({ [-1] = "-", [1] = "+" })[type], amount / 100)) ]], amount * type, ({ [-1] = "-", [1] = "+" })[type], amount / 100,
({ [-1] = "neg", [1] = "pos" })[type]))
end end
print("<br/>")
end end
print("</div>")
end) end)
end end
@ -142,7 +229,7 @@ local function r_index()
<form action="/" method="GET"> <form action="/" method="GET">
<label for="username">Username: </label> <label for="username">Username: </label>
<input type="text" name="create_user" id="username" /><br/> <input type="text" name="create_user" id="username" /><br/>
<input type="submit" value="Create" /> <input type="submit" value="Continue" />
</form> </form>
]]) ]])
print("<ul>") print("<ul>")
@ -155,26 +242,21 @@ local function r_index()
end end
local function r_create_user() local function r_create_user()
if query == nil then local username = query.create_user
return respond_error("no query") if username:match("^([%w_ -]+)$") == nil then
return respond_error("invalid username " .. username)
end end
local username = query:match("^\\?create_user=([%w_-]+)$") return redirect(string.format("/%s", urlencode(username)))
if username == nil then
return respond_error("invalid username")
end
return redirect(string.format("/%s", username))
end end
if path == "/" then if path == "/" then
if query == "?log" then if query.log then
return r_log() return r_log()
elseif query ~= nil and query:match("^\\?create_user=") then elseif query.create_user then
return r_create_user() return r_create_user()
else else
return r_index() return r_index()
end end
else else
r_user() return r_user()
end end
return respond_error("unknown route")