Example #1
0
class Account:
    def __init__(self, db: str = "Data/atmdb.db") -> Account:
        self.accountId = None
        self.balance = None
        self.isAuthorized = False
        self.sql = SQLHelper(db)

    # updates account details
    def addAccountDetails(self,
                          accountId: str,
                          balance: int,
                          isAuthorized: bool = True) -> None:
        self.accountId = accountId
        self.balance = balance
        self.isAuthorized = isAuthorized

    # update account balance in db and in memory
    # if withdrawal, change amount to negative
    # amount is added to current amount (doesn't just set the amount)
    # also update account history in db
    def updateAccountBalance(self, amount: int) -> None:
        newBalance = self.balance + amount
        self.sql.updateBalanceCmd(self.accountId, amount, newBalance)
        self.balance = newBalance

    # Clears all account details
    # This method is mainly to be used for inactive logout
    # As we can't create a new sqllite object in a different thread
    def clearAccountDetails(self) -> None:
        self.accountId = None
        self.balance = None
        self.isAuthorized = False
        self.sql = None
Example #2
0
 def __init__(self,
              inactiveTime: int = 120,
              db: str = "Data/atmdb.db") -> ATM:
     # commands that require and account to be authorized before running
     self.preauthCmds = ["withdraw", "deposit", "balance", "history"]
     self.sql = SQLHelper(db)
     self.atmBalance = self.sql.getATMBalanceCmd()
     self.inactiveTime = inactiveTime
     # timer that after inactiveTime runs inactiveLogout method
     self.timer = Timer(self.inactiveTime, self.inactiveLogout)
     self.activeTimer = False
     self.db = db
     self.account = Account(self.db)
Example #3
0
    def authorize(self, accountId: str, pin: str) -> ControllerResponse:
        response = ControllerResponse()

        # check if an account is already authorized, if one is then return
        if self.account.isAuthorized:
            message = "An account is already authorized. Logout before authorizing another account."
            response.addResponseMsg(message)
            return response

        # validate that account sql object is valid
        # it's possible that it could have been cleared
        # due to inactivity
        if self.account.sql is None:
            self.account.sql = SQLHelper(self.db)

        # search for account data
        actData = self.sql.accountSelectCmd(accountId)

        # if no account exists with the provided account id then return
        # failed authorization
        if not actData:
            message = "Authorization failed."
            response.addResponseMsg(message)
            return response

        # get pin number
        actPin = actData[2]

        # if the pin on file matches the provided pin then authorize account
        if actPin == pin:
            balance = actData[3]
            self.account.addAccountDetails(accountId, balance, True)
            message = "{} successfully authorized.".format(accountId)
        # otherwise fail authorization
        else:
            message = "Authorization failed."

        response.addResponseMsg(message)
        return response
Example #4
0
class ATMTests(unittest.TestCase):
    @classmethod
    def setUp(self):
        # create atm object with 3 second logout timer and point towards test db
        # this is mostly to be used with tests that don't require auth
        # create sql object that points towards test db
        self.atm = ATM(3, "Data/atmdb_test.db")
        self.sql = SQLHelper("Data/atmdb_test.db")

    # authorizes the first available account
    def AuthorizeAct(self, inactive: int = 3) -> ATM:
        atm = ATM(inactive, "Data/atmdb_test.db")
        data = self.sql.getSingleAccountCmd()
        accountId = data[0]
        pin = data[1]
        atm.controller("authorize {} {}".format(accountId, pin))
        return atm

    # tests authorizing a valid account
    def test_AuthorizeSuccess(self) -> None:
        print("Testing authorization of a valid account id and pin")
        # get first account id and pin in db
        data = self.sql.getSingleAccountCmd()
        accountId = data[0]
        pin = data[1]
        response = self.atm.controller("authorize {} {}".format(
            accountId, pin))
        # assert response is correct
        self.assertEqual("{} successfully authorized.".format(accountId),
                         response.message)
        # assert account is authorized
        self.assertTrue(self.atm.account.isAuthorized)
        self.atm.controller
        self.atm.controller("end")

    # tests authorizing an invalid account id
    def test_AuthorizeBadAccountId(self) -> None:
        print("Testing authorization of an invalid account id")
        response = self.atm.controller("authorize 55555 1234")
        # assert response is correct
        self.assertEqual("Authorization failed.", response.message)
        # assert account is not authorized
        self.assertFalse(self.atm.account.isAuthorized)
        self.atm.controller("end")

    # tests authorizing a valid account with an invalid pin
    def test_AuthorizationBadPin(self) -> None:
        print(
            "Testing authorization of a valid account id with an invalid pin")
        data = self.sql.getSingleAccountCmd()
        accountId = data[0]
        response = self.atm.controller("authorize {} 0000".format(accountId))
        # assert response is correct
        self.assertEqual("Authorization failed.", response.message)
        # assert account is not authorized
        self.assertFalse(self.atm.account.isAuthorized)
        self.atm.controller("end")

    # tests running through all commands, except logout & end
    # that require authorizatio with no authorization
    def test_CommandsWithNoAuthorization(self) -> None:
        print(
            "Testing running all commands (except logout & end) that require authorization with no authorization"
        )
        responseLst = list()
        # run through commads and append response to list
        responseLst.append(self.atm.controller("balance").message)
        responseLst.append(self.atm.controller("history").message)
        responseLst.append(self.atm.controller("withdraw 20").message)
        responseLst.append(self.atm.controller("deposit 20").message)

        # validate that all responses were correct
        for response in responseLst:
            self.assertTrue(response == "Authorization required.")

        self.atm.controller("end")

    # Tests a valid withdrawal
    # Validates balances are correct at the end
    # and that response is correct
    def test_ValidWithdrawal(self) -> None:
        print("Testing a valid withdrawal of $20")
        atm = self.AuthorizeAct()
        # get current balances
        atmBal = atm.atmBalance
        actBal = atm.account.balance

        # validate atm has enough money, add 100 if it doesn't
        if atmBal < 20:
            atm.updateATMBalance(100)
            atmBal = 100

        # validate account has enough money
        # add difference between 20 and account val + 1
        if actBal < 20:
            diff = 20 - atm.account.balance
            atm.account.updateAccountBalance(diff + 1)
            actBal += diff + 1

        # run withdraw command
        response = atm.controller("withdraw 20")
        # assert balances have been updated
        self.assertEqual(atmBal - 20, atm.atmBalance)
        self.assertEqual(actBal - 20, atm.account.balance)
        respMsg = "Amount dispensed: $20\nCurrent balance: {}".format(
            round(atm.account.balance, 2))
        # validate response is correct
        self.assertEqual(response.message, respMsg)
        atm.controller("end")

    # tests a withdrawal that results in an overdraft fee
    # Validates balances are correct and response message is correct
    def test_OverdraftWithdrawal(self) -> None:
        print("Testing an overdraft withdrawal")
        atm = self.AuthorizeAct()
        actBal = atm.account.balance
        atmBal = atm.atmBalance

        # if account balance is less than 15 update
        if actBal < 15:
            diff = 15 - actBal
            atm.account.updateAccountBalance(diff)
            actBal += diff

        # if balance is greater than or equal to 20 update
        elif actBal >= 20:
            diff = actBal - 19
            atm.account.updateAccountBalance(diff * -1)
            actBal -= diff

        # if atm bal if under 20 update
        if atmBal < 20:
            atm.updateATMBalance(100)
            atmBal = 100

        response = atm.controller("withdraw 20")
        # assert balances have been updated and that overdraft fee was taken out of account
        self.assertEqual(atmBal - 20, atm.atmBalance)
        self.assertEqual(actBal - 25, atm.account.balance)
        message = (
            "Amount dispensed: $20\nYou have been charged an overdraft fee of "
            "$5. Current balance: {}").format(round(atm.account.balance, 2))
        # validate response is correct
        self.assertEqual(response.message, message)
        atm.controller("end")

    # Tests scenario where atm doesn't have enough to complete full withdrawal
    # Validates balances are correct and response message is correct
    def test_InvalidAtmAmtWithdrawl(self) -> None:
        print(
            "Testing a scenario where the atm doesn't have enough to dispense full amount"
        )
        atm = self.AuthorizeAct()
        atmBal = atm.atmBalance
        actBal = atm.account.balance

        # adjust atm balance if necessary
        if atmBal != 15:
            atm.updateATMBalance(15)
            atmBal = 15

        # adjust act bal if necessary
        if actBal < 20:
            diff = 20 - actBal
            atm.account.updateAccountBalance(diff)
            actBal += diff

        response = atm.controller("withdraw 20")
        self.assertEqual(0, atm.atmBalance)
        self.assertEqual(actBal - 15, atm.account.balance)
        message = "Unable to dispense full amount requested at this time. Amount dispensed: $15\nCurrent balance: {}".format(
            round(atm.account.balance, 2))
        self.assertEqual(message, response.message)
        atm.controller("end")

    # tests scenario where atm has no money to dispense
    # validates atm balance and response
    def test_AtmEmptyWithdrawal(self) -> None:
        print("Testing scenario where atm has no money to dispense")
        atm = self.AuthorizeAct()
        atmBal = atm.atmBalance
        actBal = atm.account.balance

        # adjust atm balance if necessary
        if atmBal != 0:
            atm.updateATMBalance(0)
            atmBal = 0

        if actBal < 0:
            atm.account.updateAccountBalance(abs(actBal) + 1)
            actBal = abs(actBal) + 1

        response = atm.controller("withdraw 20")
        self.assertEqual(0, atm.atmBalance)
        message = "Unable to process your withdrawal at this time."
        self.assertEqual(response.message, message)
        atm.controller("end")

    # tests scenario where account is overdrawn
    def test_AccountOverdrawnWithdrawal(self) -> None:
        print("Testing scenario where account is overdrawn")
        atm = self.AuthorizeAct()
        actBal = atm.account.balance

        if actBal >= 0:
            diff = -1 - actBal
            atm.account.updateAccountBalance(diff)
            actBal += diff

        response = atm.controller("withdraw 20")
        self.assertEqual(actBal, atm.account.balance)
        message = "Your account is overdrawn! You may not make withdrawals at this time."
        self.assertEqual(message, response.message)
        atm.controller("end")

    # tests scenario where negative withdrawal amount given
    def test_NegativeWitdrawal(self) -> None:
        print("Testing scenarion where negative withdrawal amount is given")
        atm = self.AuthorizeAct()
        response = atm.controller("withdraw -20")
        message = "Withdrawal amount must be greater than 0 and in increments of 20."
        self.assertEqual(response.message, message)
        atm.controller("end")

    # tests scenario where an non multiple of 20 withdrawal amount given
    def test_NotMultOf20Witdrawal(self) -> None:
        print(
            "Testing scenarion where an amount that isn't a multiple of 20 is provided for withdrawal"
        )
        atm = self.AuthorizeAct()
        response = atm.controller("withdraw 15")
        message = "Withdrawal amount must be greater than 0 and in increments of 20."
        self.assertEqual(response.message, message)
        atm.controller("end")

    # tests a valid deposit of $20
    def test_ValidDeposit(self) -> None:
        print("Testing valid deposit of $20")
        atm = self.AuthorizeAct()
        atmBal = atm.atmBalance
        actBal = atm.account.balance
        response = atm.controller("deposit 20")
        self.assertEqual(atmBal + 20, atm.atmBalance)
        self.assertEqual(actBal + 20, atm.account.balance)
        message = "Current balance: {}".format(atm.account.balance)
        self.assertEqual(message, response.message)
        atm.controller("end")

    # tests an invalid deposit of 0
    def test_ZeroDeposit(self) -> None:
        print("Testing scenario where $0 is deposited")
        atm = self.AuthorizeAct()
        response = atm.controller("deposit 0")
        message = "Deposit amount must be greater than 0."
        self.assertEqual(response.message, message)
        atm.controller("end")

    # tests an invalid deposit of -5
    def test_NegativeDeposit(self) -> None:
        print("Testing scenario where $-5 is deposited")
        atm = self.AuthorizeAct()
        response = atm.controller("deposit -5")
        message = "Deposit amount must be greater than 0."
        self.assertEqual(response.message, message)
        atm.controller("end")

    # tests balance command
    def test_Balance(self) -> None:
        print("Testing balance command")
        atm = self.AuthorizeAct()
        response = atm.controller("balance")
        message = "Current balance: {}".format(atm.account.balance)
        self.assertEqual(message, response.message)
        atm.controller("end")

    # tests balance by depositing and then checking history is not null
    def test_History(self) -> None:
        print("Testing history command")
        atm = self.AuthorizeAct()
        atm.controller("deposit 20")
        response = atm.controller("history")
        self.assertIsNotNone(response.message)
        atm.controller("end")

    # tests scenario where account has no history
    # validates response is correct
    def test_NoHistory(self) -> None:
        print("Testing scenario where there is no account history")
        atm = self.AuthorizeAct()
        self.sql.clearAccountHistoryCmd(atm.account.accountId)
        response = atm.controller("history")
        self.assertEqual(response.message, "No history found")
        atm.controller("end")

    # tests logging out of valid account
    # validate authorized flag is false
    # and response message is correct
    def test_ValidLogout(self) -> None:
        print("Testing normal logout")
        atm = self.AuthorizeAct()
        accountId = atm.account.accountId
        response = atm.controller("logout")
        message = "Account {} logged out.".format(accountId)
        self.assertFalse(atm.account.isAuthorized)
        self.assertEqual(message, response.message)
        atm.controller("end")

    # tests logging out of account when one isn't logged in
    # validate authorized flag is false
    # and response message is correct
    def test_InvalidLogout(self) -> None:
        print("Testing logging out when no account is logged in")
        atm = ATM()
        response = atm.controller("logout")
        message = "No account is currently authorized."
        self.assertEqual(message, response.message)
        self.assertFalse(atm.account.isAuthorized)
        atm.controller("end")

    # tests that user is logged out after 4 seconds
    # when inactive logout is set to 3 seconds
    def test_InactiveLogout(self) -> None:
        print("Testing scenario where user is inactive and is logged out")
        atm = self.AuthorizeAct()
        sleep = Event()
        sleep.wait(4)
        self.assertFalse(atm.account.isAuthorized)

    # tests inputs that should trigger error when given while user logged in
    # asserts error flag is raised and
    def test_BadInputLoggedIn(self) -> None:
        print(
            "Testing a few scenarios where user is logged in and gives bad input"
        )
        atm = self.AuthorizeAct()
        badInput = [
            "deposit 1 2 3 4", "withdraw 5634 095376", "26235742", "2438g346"
        ]

        for bad in badInput:
            response = atm.controller(bad)
            self.assertEqual("Invalid command detected.", response.message)
            self.assertTrue(response.error)

        atm.controller("end")

    # tests inputs that should trigger error when given while user not logged in
    # asserts error flag is raised and
    def test_BadInputNotLoggedIn(self) -> None:
        print(
            "Testing a few scenarios where user is not logged in and gives bad input"
        )
        atm = ATM(3, "Data/atmdb_test.db")
        badInput = [
            "deposit 1 2 3 4", "withdraw 5634 095376", "26235742", "2438g346"
        ]

        for bad in badInput:
            response = atm.controller(bad)
            self.assertEqual("Invalid command detected.", response.message)
            self.assertTrue(response.error)

        atm.controller("end")

    # test having a user login, be logged out due to inactivity
    # login again and then withdraw
    def test_InactiveLogoutThenLoginAndWitdraw(self) -> None:
        print(
            "Testing a scenario when a user is logged out due to inactivity then is logged back and withdraws"
        )
        atm = self.AuthorizeAct()
        sleep = Event()
        sleep.wait(4)
        atm = self.AuthorizeAct()
        ogBal = atm.account.balance

        # make sure the account has enough money
        if ogBal < 20:
            diff = 20 - ogBal
            atm.account.updateAccountBalance(diff)

        # make sure atm has enough money
        if atm.atmBalance < 20:
            atm.updateATMBalance(100)

        # withdraw money and recheck balance
        response = atm.controller("withdraw 20")
        newBal = atm.account.balance
        self.assertEqual(newBal, ogBal - 20)
        message = "Amount dispensed: $20\nCurrent balance: {}".format(newBal)
        self.assertEqual(response.message, message)
        atm.controller("end")
Example #5
0
 def setUp(self):
     # create atm object with 3 second logout timer and point towards test db
     # this is mostly to be used with tests that don't require auth
     # create sql object that points towards test db
     self.atm = ATM(3, "Data/atmdb_test.db")
     self.sql = SQLHelper("Data/atmdb_test.db")
Example #6
0
class ATM:
    # constructor, inactive logout time by default is 2 minutes
    # db by default is atmdb
    def __init__(self,
                 inactiveTime: int = 120,
                 db: str = "Data/atmdb.db") -> ATM:
        # commands that require and account to be authorized before running
        self.preauthCmds = ["withdraw", "deposit", "balance", "history"]
        self.sql = SQLHelper(db)
        self.atmBalance = self.sql.getATMBalanceCmd()
        self.inactiveTime = inactiveTime
        # timer that after inactiveTime runs inactiveLogout method
        self.timer = Timer(self.inactiveTime, self.inactiveLogout)
        self.activeTimer = False
        self.db = db
        self.account = Account(self.db)

    # updates atm balance in memory and in db
    # to specified amount
    def updateATMBalance(self, amount: int):
        self.sql.updateATMBalance(amount)
        self.atmBalance = amount

    # updates atm and account balances
    def updateBalances(self,
                       amount: int,
                       withdrawal: bool,
                       overdraft: bool = False) -> None:
        actAmt = amount
        atmAmt = amount

        # if this transaction overdrafts the account subtract an additional 5
        if overdraft:
            actAmt += 5

        # if the is is a withdrawal turn amount negative
        if withdrawal:
            actAmt *= -1
            atmAmt *= -1

        # run methods to update atm and account balances
        newAtmBal = self.atmBalance + atmAmt
        self.updateATMBalance(newAtmBal)
        self.account.updateAccountBalance(actAmt)

    # uses accountSelectCmd from sqlhelper to get account using account id
    # checks that the provided pin matches the pin on file
    # if pin matches account is authorized, otherwise account is not authorized
    def authorize(self, accountId: str, pin: str) -> ControllerResponse:
        response = ControllerResponse()

        # check if an account is already authorized, if one is then return
        if self.account.isAuthorized:
            message = "An account is already authorized. Logout before authorizing another account."
            response.addResponseMsg(message)
            return response

        # validate that account sql object is valid
        # it's possible that it could have been cleared
        # due to inactivity
        if self.account.sql is None:
            self.account.sql = SQLHelper(self.db)

        # search for account data
        actData = self.sql.accountSelectCmd(accountId)

        # if no account exists with the provided account id then return
        # failed authorization
        if not actData:
            message = "Authorization failed."
            response.addResponseMsg(message)
            return response

        # get pin number
        actPin = actData[2]

        # if the pin on file matches the provided pin then authorize account
        if actPin == pin:
            balance = actData[3]
            self.account.addAccountDetails(accountId, balance, True)
            message = "{} successfully authorized.".format(accountId)
        # otherwise fail authorization
        else:
            message = "Authorization failed."

        response.addResponseMsg(message)
        return response

    # validate that account is authorized the withdraw amount
    # validate that atm and account have enough money
    def withdraw(self, amount: int) -> ControllerResponse:
        response = ControllerResponse()

        # if the amount is not greater than 0 and not an increment of 20 update response message
        # exit immediately
        if amount <= 0 or amount % 20 != 0:
            message = "Withdrawal amount must be greater than 0 and in increments of 20."
            response.addResponseMsg(message)
            return response
        # if the account is overdrawn update the response message
        # and exit immediately
        elif self.account.balance < 0:
            message = "Your account is overdrawn! You may not make withdrawals at this time."
            response.addResponseMsg(message)
            return response
        # if the atm has no money update response message and return
        elif self.atmBalance == 0:
            message = "Unable to process your withdrawal at this time."
            response.addResponseMsg(message)
            return response

        message = ""

        # if there isn't enough in the atm, update amount requested to atm balance
        # prepend unable to dispense full amount message to return message
        if amount > self.atmBalance:
            message = "Unable to dispense full amount requested at this time. "
            amount = self.atmBalance

        # if there is enough in the account
        # update account and atm balance
        if amount <= self.account.balance:
            self.updateBalances(amount, True)
            message += "Amount dispensed: ${}\nCurrent balance: {}".format(
                amount, round(self.account.balance, 2))
        # if there is money in the account but not enough
        # add an extra 5 to withdrawal amount
        # update account and atm balance
        elif 0 <= self.account.balance < amount:
            self.updateBalances(amount, True, True)
            message += (
                "Amount dispensed: ${}\nYou have been charged an overdraft fee of "
                "$5. Current balance: {}").format(
                    amount, round(self.account.balance, 2))

        # update response message
        response.addResponseMsg(message)
        return response

    # deposits provided amount into bank account
    def deposit(self, amount: int) -> ControllerResponse:
        if amount > 0:
            self.updateBalances(amount, False)
            message = "Current balance: {}".format(
                round(self.account.balance, 2))
        else:
            message = "Deposit amount must be greater than 0."

        # update response and return
        response = ControllerResponse()
        response.addResponseMsg(message)
        return response

    # Finds balance of authorized account
    def getBalance(self) -> ControllerResponse:
        response = ControllerResponse()
        response.addResponseMsg("Current balance: {}".format(
            round(self.account.balance, 2)))
        return response

    # get history from db then format into string
    def getHistory(self) -> ControllerResponse:
        message = ""
        sqlData = self.sql.getHistoryCmd(self.account.accountId)

        # if no history found update message
        # otherwise grab history
        if len(sqlData) == 0:
            message = "No history found"
        else:
            for row in sqlData:
                message += "{} {} {} {}\n".format(row[0], row[1],
                                                  round(row[2], 2),
                                                  round(row[3], 2))

        response = ControllerResponse()
        response.addResponseMsg(message)
        return response

    # if an account is logged in then log out and update response message
    # if no account is logged in then just update response message
    def logout(self) -> ControllerResponse:
        if self.account.isAuthorized:
            message = "Account {} logged out.".format(self.account.accountId)
            self.account = Account(self.db)
        else:
            message = "No account is currently authorized."

        response = ControllerResponse()
        response.addResponseMsg(message)
        return response

    # method that is called by timer when time is up
    # logs out user and sets active timer flag to false
    def inactiveLogout(self) -> None:
        self.account.clearAccountDetails()
        self.activeTimer = False
        self.timer = Timer(self.inactiveTime, self.inactiveLogout)

    # starts the inactive timer if one isn't running and account is authorized
    def startInactiveTimer(self) -> None:
        if self.account.isAuthorized and not self.activeTimer:
            self.timer.start()
            self.activeTimer = True

    # stops the inactive timer if one is running
    def stopInactiveTimer(self) -> None:
        # if a timer is running, cancel timer, reset flag
        # and create new timer object
        if self.activeTimer:
            self.timer.cancel()
            self.activeTimer = False
            self.timer = Timer(self.inactiveTime, self.inactiveLogout)

    # end program
    def endProgram(self) -> ControllerResponse:
        response = ControllerResponse()
        response.setEndFlag()
        response.addResponseMsg("Goodbye!")
        return response

    # logs error to db
    def logError(self, error: Exception) -> None:
        errorMsg = str(error)
        # escape single quotes
        errorMsg = errorMsg.replace("'", "''")
        self.sql.logErrorCmd(self.account.accountId, errorMsg)

    # validates user input
    # checks length and data types
    def validateInput(self, usrInput: str) -> List[object]:
        # strip and split user input
        cmdParts = usrInput.strip().split()

        # no command should have over 3 arguments, raise exception
        if len(cmdParts) > 3:
            raise Exception(
                "Too many arguments detected in command: {}".format(usrInput))

        firstPart = cmdParts[0].lower()
        # commands that should only have 2 parts
        twoPartCmds = ["withdraw", "deposit"]
        onePartCmds = ["balance", "history", "logout", "end"]

        # if the command has three parts it should be authorize
        if len(cmdParts) == 3 and firstPart != "authorize":
            raise Exception(
                "Too many arguments detected in command: {}".format(usrInput))
        # if it has two pasts it should just be withdraw or deposit
        elif len(cmdParts) == 2 and firstPart not in twoPartCmds:
            raise Exception(
                "Too many arguments detected in command: {}".format(usrInput))
        # if in one part commands, should only be one command
        elif firstPart in onePartCmds and len(cmdParts) != 1:
            raise Exception(
                "Too many arguments detected in command: {}".format(usrInput))

        validCmds = list()
        validCmds.append(firstPart)

        # is this is an authorize command then list should have strings
        if firstPart == "authorize":
            for i in range(1, len(cmdParts)):
                argVal = cmdParts[i].strip()
                validCmds.append(argVal)

        # otherwise first command should be strings
        # all others should be ints if len > 1
        elif len(cmdParts) > 1:
            for i in range(1, len(cmdParts)):
                argVal = int(cmdParts[i].strip())
                validCmds.append(argVal)

        return validCmds

    # controls logic flow of class
    # routes to different methods based on valid user input
    # starts and stops inactivity timer
    def controller(self, userInput: str) -> ControllerResponse:
        self.stopInactiveTimer()

        # minimal error handling for simplicity
        # one try block, if error occurs log and return generic response
        try:
            # raise exception
            if len(userInput.strip()) == 0:
                raise Exception("No input detected.")
            # parse commands if valid, exception raised if not valid
            cmds = self.validateInput(userInput)
            initArg = cmds[0]

            # if the command is in the list of commands that need authorization
            # validate that the account is authorized
            if initArg in self.preauthCmds:
                # if the account is authorized then route and run command
                if self.account.isAuthorized:
                    if initArg == "withdraw":
                        response = self.withdraw(cmds[1])
                    elif initArg == "deposit":
                        response = self.deposit(cmds[1])
                    elif initArg == "balance":
                        response = self.getBalance()
                    elif initArg == "history":
                        response = self.getHistory()
                # if the account isn't authorized, update response
                else:
                    response = ControllerResponse()
                    response.addResponseMsg("Authorization required.")
            # if command doesn't need preauth then run them
            elif initArg == "authorize":
                response = self.authorize(cmds[1], cmds[2])
            elif initArg == "logout":
                response = self.logout()
            elif initArg == "end":
                response = self.endProgram()
            # otherwise command isn't recognized, throw error
            else:
                raise Exception(
                    "Invalid command detected: {}".format(userInput))

        # if there is an error, log to db and update controller message
        except Exception as e:
            self.logError(e)
            message = "Invalid command detected."
            response = ControllerResponse()
            response.addResponseMsg(message)
            response.updateErrorFlag(True)

        # start inactive timer unless if program is ending
        if not response.end:
            self.startInactiveTimer()

        return response
Example #7
0
 def __init__(self, db: str = "Data/atmdb.db") -> Account:
     self.accountId = None
     self.balance = None
     self.isAuthorized = False
     self.sql = SQLHelper(db)