#!/usr/bin/env luajit local function escape(s) return s:gsub("<", "<"):gsub("<", "<") 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 function load_config() local log = io.open("config", "r") if log == nil then return {} end local config = {} for l in log:lines("l") do if l ~= "" and l[0] ~= "#" then local key, value = string.match(l, "^([^=]+)=([^=]*)") if key ~= nil and value ~= nil then config[key] = value end end end return config end local config = load_config() 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.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 = [[ 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) print(string.format("Status: %d", status)) print("Content-Type: text/html") print("") print(string.format([[
Error: %s
", escape(message))) end) end local function redirect(path) print("Status: 307") print(string.format("Location: %s", path)) print() end 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 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 time, username, amount, comment = string.match(l, "(%d+),([%w_ -]+),(-?%d+),([%w_ -]*)") return tonumber(time), username, tonumber(amount), comment 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 users = {} for _, username, amount, _ in read_log() do users[username] = (users[username] or 0) + amount end return users end local function last_txns() local users = {} for time, username, _, _ in read_log() do users[username] = time end return users end local function error_box(message) return string.format([[Error: %s
Transaction successful: %.02f€ (%s)
This user account does not exist yet. It will only be created after the first transaction.
Current balance: %.02f€
]], balance >= 0 and "pos" or "neg", balance / 100)) print(string.format([[Last transaction added %s ago. View user log ]], format_duration(os.time() - last_txn), username)) end print([[
]]) print("Time | Username | Amount | Comment |
---|---|---|---|
%d (%s ago) | %s | %.02f€ | %s |