Added transactions

This commit is contained in:
Andrew Lalis 2023-08-29 15:36:53 -04:00
parent d5b2016dc3
commit ffd620f172
2 changed files with 89 additions and 16 deletions

View File

@ -9,6 +9,7 @@ local client = {}
client.state = {
auth = nil,
hostId = nil,
securityKey = nil,
timeout = 3
}
@ -28,18 +29,28 @@ local function request(command, data)
return requestRaw({command = command, data = data})
end
local function requestAuth(command, data)
local function requestAuth(command, data, secure)
secure = secure or false
if not client.loggedIn() then
return {success = false, error = "Client not logged in"}
end
return requestRaw({command = command, auth = client.state.auth, data = data})
local authInfo = {
username = client.state.auth.username,
password = client.state.auth.password
}
if secure and not client.state.securityKey then
return {success = false, error = "Missing security key for secure request."}
end
autInfo.key = client.state.securityKey
return requestRaw({command = command, auth = authInfo, data = data})
end
-- Base functions
function client.init(modemName, host)
function client.init(modemName, host, securityKey)
rednet.open(modemName)
client.state.hostId = rednet.lookup("BANK", host)
client.state.securityKey = securityKey or nil
return client.state.hostId ~= nil
end
@ -103,4 +114,12 @@ function client.renameAccount(accountId, newName)
return response.success, response.error
end
function client.recordTransaction(accountId, amount, description)
local response = requestAuth("RECORD_TRANSACTION", {accountId = accountId, amount = amount, description = description}, true)
if not response.success then
return nil, response.error
end
return response.data
end
return client

View File

@ -55,6 +55,10 @@ local function validateUsername(name)
)
end
local function validateTransactionDescription(desc)
return string.find(desc, "^%w+[ !%.%w]*$") ~= nil and #desc <= 64
end
local function userDir(name)
return fs.combine(USERS_DIR, name)
end
@ -102,13 +106,29 @@ local function saveAccounts(name, accounts)
writeJSON(userAccountsFile(name), accounts)
end
local function findAccountById(accounts, id)
for i, account in pairs(accounts) do
if account.id == id then
return account
end
end
return nil
end
local function findAccountByName(accounts, name)
for i, account in pairs(accounts) do
if account.name == name then
return account
end
end
return nil
end
local function createAccount(username, accountName)
local accounts = getAccounts(username)
for i, account in pairs(accounts) do
if account.name == accountName then
if findAccountByName(accounts, accountName) then
return false, "Duplicate account name"
end
end
local newAccount = {
id = randomAccountId(),
name = accountName,
@ -140,15 +160,11 @@ end
local function renameAccount(username, accountId, newName)
local accounts = getAccounts(username)
local targetAccount = nil
for i, account in pairs(accounts) do
if account.id == accountId then
targetAccount = account
elseif account.name == newName then
local targetAccount = findAccountById(accounts, accountId)
if not targetAccount then return false, "Account not found" end
if findAccountByName(accounts, newName) ~= nil then
return false, "Duplicate account name"
end
end
if not targetAccount then return false, "Account not found" end
targetAccount.name = newName
saveAccounts(accounts)
log("Renamed user " .. username .. " account " .. accountId .. " to " .. newName)
@ -188,6 +204,32 @@ local function renameUser(oldName, newName)
return true
end
local function recordTransaction(username, accountId, amount, description)
if not validateTransactionDescription(description) then return false, "Invalid transaction description" end
if not userExists(username) then return false, "User doesn't exist" end
local accounts = getAccounts(username)
local account = findAccountById(accounts, accountId)
if account == nil then return false, "Account doesn't exist" end
if account.balance + amount < 0 then return false, "Insufficient funds" end
-- Everything is OK, record the transaction.
local tx = {
amount = amount,
description = description,
timestamp = os.epoch("utc")
}
local f = io.open(accountTransactionsFile(username, accountId), "a")
local txStr = tostring(tx.amount)..";"..tostring(tx.timestamp)..";"..tx.description
f:write(txStr .. string.rep(" ", 99 - #txStr) .. "\n")
f:close()
if fs.getSize(accountTransactionsFile(username, accountId)) % 100 ~= 0 then
log("WARNING! Transaction file for account " .. accountId .. " is not consistent!")
end
account.balance = account.balance + amount
saveAccounts(username, accounts)
os.queueEvent("bank_account_balance", username, accountId, account.balance)
return true, tx
end
local function initSecurityKey()
-- Initialize security key
local SECURITY_KEY_FILE = "key.txt"
@ -290,6 +332,17 @@ local function handleRenameUserAccount(msg)
return {success = success, error = errorMsg}
end
local function handleRecordTransactionToAccount(msg)
if not msg.data or not msg.data.amount or not msg.data.description or not msg.data.accountId then
return {success = false, error = "Invalid request. Requires data.amount and data.description and data.accountId."}
end
local success, errorMsgOrTx = recordTransaction(msg.auth.username, msg.data.accountId, msg.data.amount, msg.data.description)
if not success then
return {success = false, error = errorMsgOrTx}
end
return {success = true, data = errorMsgOrTx}
end
-- A registry of all possible BANK requests, and their handler functions.
local BANK_REQUESTS = {
["STATUS"] = handleGetStatus,
@ -299,7 +352,8 @@ local BANK_REQUESTS = {
["GET_ACCOUNTS"] = authProtect(handleGetUserAccounts),
["CREATE_ACCOUNT"] = authProtect(handleCreateUserAccount),
["DELETE_ACCOUNT"] = authProtect(handleDeleteUserAccount),
["RENAME_ACCOUNT"] = authProtect(handleRenameUserAccount)
["RENAME_ACCOUNT"] = authProtect(handleRenameUserAccount),
["RECORD_TRANSACTION"] = authProtect(handleRecordTransactionToAccount, true)
}
local function handleBankMessage(remoteId, msg)