forge/arma/server/addons/bank/functions/fnc_initValidator.sqf
Jacob Schmidt 6c0ce9e867 refactor(bank): split monolithic store into focused modules; fix locker grant for attachments
- Split BankBaseStore into SessionManager, Messenger, Model, Store, Validator
- Extract validation logic into BankValidator with try/catch and per-action methods
- Remove duplicate notifications from transaction actions
- Update event handlers to call validator first, forward context to store/session
- Fix locker grantItems: add missing 'attachment' category mapping to 'item'
- Fix locker grantItems: replace exitWith with if/else to prevent skipping remaining items

Co-Authored-By: Oz <oz-agent@warp.dev>
2026-03-16 10:54:25 -05:00

260 lines
10 KiB
Plaintext

#include "..\script_component.hpp"
/*
* File: fnc_validator.sqf
* Author: IDSolutions
* Date: 2026-03-16
* Last Update: 2026-03-16
* Public: No
*
* Description:
* Initializes the bank validator for pre-checking action payloads
* before they reach the bank store. Each method uses try/catch to
* validate inputs and state, sending a notice to the player on
* failure and returning false. On success returns a context hashmap
* containing resolved data (account, balances, etc.) for the store.
*
* Parameter(s):
* None
*
* Returns:
* Validator object [HASHMAP OBJECT]
*
* Example(s):
* call forge_server_bank_fnc_validator
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(BankValidator) = createHashMapObject [[
["#type", "BankValidator"],
["resolveAccount", compileFinal {
params [["_uid", "", [""]]];
private _account = GVAR(Registry) getOrDefault [_uid, createHashMap];
if (_account isEqualTo createHashMap) then {
throw "Bank account data is unavailable.";
};
_account
}],
["validateDeposit", compileFinal {
params [["_uid", "", [""]], ["_amount", 0, [0]]];
private _context = createHashMap;
[_uid, _amount] try {
if (_uid isEqualTo "") then { throw "Empty/Invalid UID!" };
if (_amount <= 0) then { throw "Enter a valid deposit amount." };
private _session = GVAR(BankSessionManager) call ["getSessionState", [_uid]];
if ((_session getOrDefault ["mode", "bank"]) isEqualTo "atm") then {
if !(_session getOrDefault ["atmAuthorized", false]) then {
throw "ATM authorization is required before deposit.";
};
};
private _account = _self call ["resolveAccount", [_uid]];
private _bank = _account getOrDefault ["bank", 0];
private _cash = _account getOrDefault ["cash", 0];
if (_cash < _amount) then { throw "Cash on hand cannot cover that deposit." };
_context set ["account", _account];
_context set ["bank", _bank];
_context set ["cash", _cash];
} catch {
["ERROR", format ["Deposit validation failed: %1", _exception]] call EFUNC(common,log);
GVAR(BankMessenger) call ["sendNotice", [_uid, "error", _exception]];
};
if (_context isEqualTo createHashMap) exitWith { false };
_context
}],
["validateWithdraw", compileFinal {
params [["_uid", "", [""]], ["_amount", 0, [0]]];
private _context = createHashMap;
[_uid, _amount] try {
if (_uid isEqualTo "") then { throw "Empty/Invalid UID!" };
if (_amount <= 0) then { throw "Enter a valid withdrawal amount." };
private _session = GVAR(BankSessionManager) call ["getSessionState", [_uid]];
if ((_session getOrDefault ["mode", "bank"]) isEqualTo "atm") then {
if !(_session getOrDefault ["atmAuthorized", false]) then {
throw "ATM authorization is required before withdrawal.";
};
};
private _account = _self call ["resolveAccount", [_uid]];
private _bank = _account getOrDefault ["bank", 0];
private _cash = _account getOrDefault ["cash", 0];
if (_bank < _amount) then { throw "Bank balance cannot cover that withdrawal." };
_context set ["account", _account];
_context set ["bank", _bank];
_context set ["cash", _cash];
} catch {
["ERROR", format ["Withdraw validation failed: %1", _exception]] call EFUNC(common,log);
GVAR(BankMessenger) call ["sendNotice", [_uid, "error", _exception]];
};
if (_context isEqualTo createHashMap) exitWith { false };
_context
}],
["validateTransfer", compileFinal {
params [["_uid", "", [""]], ["_target", "", [""]], ["_from", "", [""]], ["_amount", 0, [0]]];
private _context = createHashMap;
[_uid, _target, _from, _amount] try {
if (_uid isEqualTo "") then { throw "Empty/Invalid UID!" };
if (_uid isEqualTo _target) then { throw "You cannot transfer funds to yourself." };
if (_amount <= 0) then { throw "Enter a valid transfer amount." };
private _session = GVAR(BankSessionManager) call ["getSessionState", [_uid]];
if ((_session getOrDefault ["mode", "bank"]) isNotEqualTo "bank") then {
throw "Transfers are only available from the full bank interface.";
};
private _account = _self call ["resolveAccount", [_uid]];
private _targetAccount = GVAR(Registry) getOrDefault [_target, createHashMap];
if (_targetAccount isEqualTo createHashMap) then {
_targetAccount = GVAR(BankStore) call ["init", [_target]];
};
if (_targetAccount isEqualTo createHashMap) then {
throw "Selected transfer recipient is unavailable.";
};
private _sourceField = ["bank", "cash"] select (toLowerANSI _from isEqualTo "cash");
private _selected = _account getOrDefault [_sourceField, 0];
if (_selected < _amount) then {
private _message = [
"Bank balance cannot cover that transfer.",
"Cash on hand cannot cover that transfer."
] select (_sourceField isEqualTo "cash");
throw _message;
};
_context set ["account", _account];
_context set ["targetAccount", _targetAccount];
_context set ["sourceField", _sourceField];
_context set ["sourceBalance", _selected];
_context set ["targetBank", _targetAccount getOrDefault ["bank", 0]];
} catch {
["ERROR", format ["Transfer validation failed: %1", _exception]] call EFUNC(common,log);
GVAR(BankMessenger) call ["sendNotice", [_uid, "error", _exception]];
};
if (_context isEqualTo createHashMap) exitWith { false };
_context
}],
["validateDepositEarnings", compileFinal {
params [["_uid", "", [""]], ["_amount", 0, [0]]];
private _context = createHashMap;
[_uid, _amount] try {
if (_uid isEqualTo "") then { throw "Empty/Invalid UID!" };
private _session = GVAR(BankSessionManager) call ["getSessionState", [_uid]];
if ((_session getOrDefault ["mode", "bank"]) isNotEqualTo "bank") then {
throw "Earnings deposits are only available from the full bank interface.";
};
if (_amount <= 0) then { throw "No earnings are available to deposit." };
private _account = _self call ["resolveAccount", [_uid]];
private _bank = _account getOrDefault ["bank", 0];
private _earnings = _account getOrDefault ["earnings", 0];
if (_earnings < _amount) then { throw "Pending earnings cannot cover that deposit request." };
_context set ["account", _account];
_context set ["bank", _bank];
_context set ["earnings", _earnings];
} catch {
["ERROR", format ["DepositEarnings validation failed: %1", _exception]] call EFUNC(common,log);
GVAR(BankMessenger) call ["sendNotice", [_uid, "error", _exception]];
};
if (_context isEqualTo createHashMap) exitWith { false };
_context
}],
["validatePayment", compileFinal {
params [["_uid", "", [""]], ["_amount", 0, [0]]];
private _context = createHashMap;
[_uid, _amount] try {
if (_uid isEqualTo "") then { throw "Empty/Invalid UID!" };
if (_amount <= 0) then { throw "Enter a valid payment amount." };
private _account = _self call ["resolveAccount", [_uid]];
private _bank = _account getOrDefault ["bank", 0];
_context set ["account", _account];
_context set ["bank", _bank];
} catch {
["ERROR", format ["Payment validation failed: %1", _exception]] call EFUNC(common,log);
GVAR(BankMessenger) call ["sendNotice", [_uid, "error", _exception]];
};
if (_context isEqualTo createHashMap) exitWith { false };
_context
}],
["validateSubmitPin", compileFinal {
params [["_uid", "", [""]], ["_pin", "", [""]]];
private _context = createHashMap;
[_uid, _pin] try {
if (_uid isEqualTo "") then { throw "Empty/Invalid UID!" };
private _session = GVAR(BankSessionManager) call ["getSessionState", [_uid]];
if ((_session getOrDefault ["mode", "bank"]) isNotEqualTo "atm") then {
_session = GVAR(BankSessionManager) call ["setSessionState", [_uid, createHashMapFromArray [
["atmAuthorized", false],
["mode", "atm"]
]]];
};
private _account = GVAR(Registry) getOrDefault [_uid, createHashMap];
if (_account isEqualTo createHashMap) then {
_account = GVAR(BankStore) call ["init", [_uid]];
};
if (_account isEqualTo createHashMap) then {
throw "Bank account data is unavailable.";
};
private _enteredPin = _pin;
if !(_enteredPin isEqualType "") then {
_enteredPin = str _enteredPin;
};
if ((count _enteredPin) isNotEqualTo 4) then {
throw "Enter your four-digit access PIN.";
};
private _accountPin = str (_account getOrDefault ["pin", 1234]);
if (_enteredPin isNotEqualTo _accountPin) then {
GVAR(BankSessionManager) call ["setSessionState", [_uid, createHashMapFromArray [["atmAuthorized", false]]]];
throw "Incorrect PIN.";
};
_context set ["account", _account];
_context set ["session", _session];
} catch {
["ERROR", format ["SubmitPin validation failed: %1", _exception]] call EFUNC(common,log);
GVAR(BankMessenger) call ["sendNotice", [_uid, "error", _exception]];
GVAR(BankStore) call ["hydrateSession", [_uid, "atm", false]];
};
if (_context isEqualTo createHashMap) exitWith { false };
_context
}]
]];
GVAR(BankValidator)