diff --git a/api.yml b/api.yml index 82aa54b..957d966 100644 --- a/api.yml +++ b/api.yml @@ -105,63 +105,7 @@ paths: description: Old password incorrect '404': description: client_id not found - /Client: - post: - tags: - - client - summary: Add a new client - description: Add a new client to the system - operationId: manager.add_client - parameters: - - name: name - in: query - description: Client Name - required: true - schema: - type: string - - name: birthdate - in: query - description: Client Birthdate (dd-mm-yyyy) - required: true - schema: - type: string - - name: address - in: query - description: Client Address - required: false - schema: - type: string - - name: phone_number - in: query - description: Client Phone Number - required: true - schema: - type: string - - name: email - in: query - description: Client Email Address - required: true - schema: - type: string - - name: password - in: query - description: Client Password - required: true - schema: - type: string - - name: notes - in: query - description: Notes about client - required: false - schema: - type: string - responses: - '200': - description: "Client created" - '400': - description: Invalid input - '422': - description: Validation exception + /Client/Client: put: tags: - client @@ -240,27 +184,6 @@ paths: description: Invalid Client ID supplied '404': description: Client not found - delete: - tags: - - client - summary: Delete a client by ID - description: Delete a client by ID - operationId: manager.delete_client - parameters: - - name: client_id - in: query - description: ID of client to delete - required: true - schema: - type: string - format: int32 - responses: - '200': - description: Successful operation - '400': - description: Invalid Client ID supplied - '404': - description: Client not found /Account: post: tags: @@ -361,27 +284,6 @@ paths: description: Invalid Account ID supplied '404': description: Account not found - delete: - tags: - - account - summary: Delete an account by ID - description: Delete an account by ID - operationId: manager.delete_account - parameters: - - name: account_id - in: query - description: ID of account to delete - required: true - schema: - type: string - format: int32 - responses: - '200': - description: Successful operation - '400': - description: Invalid account_id supplied - '404': - description: Account not found /Transaction: get: tags: @@ -473,7 +375,7 @@ paths: description: Invalid input '404': description: No transactions found - /Manager/Interest: + /Admin/Interest: post: tags: - admin @@ -522,7 +424,7 @@ paths: description: Invalid input '422': description: Validation exception - /Manager/Clients: + /Admin/Clients: get: tags: - admin @@ -540,7 +442,7 @@ paths: description: Invalid input '404': description: No clients found - /Manager/Accounts: + /Admin/Accounts: get: tags: - admin @@ -558,7 +460,7 @@ paths: description: Invalid input '404': description: No accounts found - /Manager/Transactions: + /Admin/Transactions: get: tags: - admin @@ -576,7 +478,7 @@ paths: description: Invalid input '404': description: No transactions found - /Manager/Hash: + /System/Hash: get: tags: - system @@ -600,8 +502,8 @@ paths: '400': description: Invalid input '401': - description: Unauthorized - /Manager/Timestamp: + description: Unauthorised + /System/Timestamp: get: tags: - system @@ -618,7 +520,185 @@ paths: '400': description: Invalid input '401': - description: Unauthorized + description: Unauthorised + /Admin/Balance: + get: + tags: + - admin + summary: Test the balance of all accounts + description: Tests the balance of all accounts and alerts of any discrepancies + operationId: manager.test_account_balances + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: string + '401': + description: Unauthorised + /System/Initialise: + get: + tags: + - system + summary: Initialise the system + description: Initialises the system with test data + operationId: manager.initialise_database + parameters: + - name: password + in: query + description: Password to initialise the system + required: true + schema: + type: string + responses: + '200': + description: Successful operation + '400': + description: Database not empty, this function cannot be used + /Admin/Promote: + put: + tags: + - admin + summary: Promote a client to administrator + description: Promote a client to administrator + operationId: manager.promote_to_admin + parameters: + - name: client_id + in: query + description: ID of client to promote + required: true + schema: + type: string + responses: + '200': + description: Successful operation + '401': + description: Unauthorised + '404': + description: Client not found + /Admin/Demote: + put: + tags: + - admin + summary: Demote a client from administrator + description: Demote a client from administrator + operationId: manager.demote_from_admin + parameters: + - name: client_id + in: query + description: ID of client to demote + required: true + schema: + type: string + responses: + '200': + description: Successful operation + '401': + description: Unauthorised + '404': + description: Client not found + /Admin/Client: + post: + tags: + - admin + summary: Add a new client + description: Add a new client to the system + operationId: manager.add_client + parameters: + - name: name + in: query + description: Client Name + required: true + schema: + type: string + - name: birthdate + in: query + description: Client Birthdate (dd-mm-yyyy) + required: true + schema: + type: string + - name: address + in: query + description: Client Address + required: false + schema: + type: string + - name: phone_number + in: query + description: Client Phone Number + required: true + schema: + type: string + - name: email + in: query + description: Client Email Address + required: true + schema: + type: string + - name: password + in: query + description: Client Password + required: true + schema: + type: string + - name: notes + in: query + description: Notes about client + required: false + schema: + type: string + responses: + '200': + description: "Client created" + '400': + description: Invalid input + '422': + description: Validation exception + /Delete/Client: + delete: + tags: + - admin + summary: Delete a client by ID + description: Delete a client by ID + operationId: manager.delete_client + parameters: + - name: client_id + in: query + description: ID of client to delete + required: true + schema: + type: string + format: int32 + responses: + '200': + description: Successful operation + '400': + description: Invalid Client ID supplied + '404': + description: Client not found + /Delete/Account: + delete: + tags: + - admin + summary: Delete an account by ID + description: Delete an account by ID + operationId: manager.delete_account + parameters: + - name: account_id + in: query + description: ID of account to delete + required: true + schema: + type: string + format: int32 + responses: + '200': + description: Successful operation + '400': + description: Invalid account_id supplied + '404': + description: Account not found components: schemas: Client: diff --git a/bank.db b/bank.db index 1456f1c..60ab951 100644 Binary files a/bank.db and b/bank.db differ diff --git a/bank.ini b/bank.ini index ebe7c20..adecc92 100644 --- a/bank.ini +++ b/bank.ini @@ -1,5 +1,5 @@ [database] -name=test_database.db +name=bank.db [api_file] name=api.yml diff --git a/manager.py b/manager.py index 75a90a0..443d4db 100644 --- a/manager.py +++ b/manager.py @@ -91,15 +91,6 @@ def get_client(client_id:str): # Returns a specific client in the database return jsonify({"name": client.name, "birthdate": client.birthdate, "opening_timestamp": client.opening_timestamp, "address": client.address, "phone_number": client.phone_number, "email": client.email}), 200 return jsonify({"error": "Client not found"}), 404 -@login_required -def add_client(name:str, birthdate:str, address:str, phone_number:str, email:str, password:str, **kwargs): # Adds a new client to the database - client_id = generate_uuid_short() - notes = kwargs.get("notes", None) - new_client = Client(client_id, name, birthdate, timestamp(), address, phone_number, email, hash_password(password), notes, 1, 0, None) - session.add(new_client) - session.commit() - return f"New client has been added: name: {name}, uuid: {client_id} ", 200 - @login_required def update_client(client_id:str, **kwargs): # Updates a client in the database current_client_id, is_admin = get_current_client() @@ -331,33 +322,78 @@ def apply_fee(account_id:int, fee:float): @admin_required def delete_transaction(transaction_id:int): DELETE_TRANSACTION = "DELETE FROM transaction WHERE transaction_id=?" - from api import session, Transaction - for transaction in session.query(Transaction).all(): - if transaction.transaction_id == transaction_id: - input(f"Are you sure you would like permanenty delete transaction ID: {transaction_id}? WARNING: This action can not be reversed. (Y/N) ") - if input == "Y"or input == "y": - session.execute(DELETE_TRANSACTION, (transaction_id)) - print(f"Transaction ID: {transaction_id} has been removed.") - else: - return f"Transaction ID: {transaction_id} has NOT been removed." - return - return f"Transaction ID: {transaction_id} is not found." + return @admin_required def test_account_balances(): - # Get all accounts - all_accounts = get_all_accounts() + # Get all transactions from the database + all_transactions = session.query(Transaction).all() + + # Initialize a dictionary to store the calculated balance for each account + calculated_balances = {} + + # Go through each transaction + for transaction in all_transactions: + # If the account ID of the transaction is not in the dictionary, add it with a balance of 0 + if transaction.account_id not in calculated_balances: + calculated_balances[transaction.account_id] = 0 + + # Update the calculated balance for the account + if transaction.transaction_type == 'Deposit': + calculated_balances[transaction.account_id] += transaction.amount + elif transaction.transaction_type == 'Withdrawal': + calculated_balances[transaction.account_id] -= transaction.amount + + # Get all accounts from the database + all_accounts = session.query(Account).all() + + # Initialize a list to store the discrepancies + discrepancies = [] # Go through each account for account in all_accounts: - # Calculate the balance based on the transactions - calculated_balance = 0 - for transaction in account.get_transactions(): - if transaction.transaction_type == 'Deposit': - calculated_balance += transaction.amount - elif transaction.transaction_type == 'Withdrawal': - calculated_balance -= transaction.amount + # If the calculated balance doesn't match the stored balance, add the discrepancy to the list + if calculated_balances.get(account.account_id, 0) != account.balance: + discrepancies.append({"error": f"Alert: Account {account.account_id} has a balance discrepancy. Stored balance is {account.balance}, but calculated balance is {calculated_balances.get(account.account_id, 0)}."}) - # Check if the calculated balance matches the stored balance - if calculated_balance != account.balance: - print(f"Alert: Account {account.account_id} has a balance discrepancy. Stored balance is {account.balance}, but calculated balance is {calculated_balance}.") + # Return the list of discrepancies + return jsonify(discrepancies), 200 + + +@admin_required +def add_client(name:str, birthdate:str, address:str, phone_number:str, email:str, password:str, **kwargs): # Adds a new client to the database + client_id = generate_uuid_short() + notes = kwargs.get("notes", None) + new_client = Client(client_id, name, birthdate, timestamp(), address, phone_number, email, hash_password(password), notes, 1, 0, None) + session.add(new_client) + session.commit() + return client_id, 200 + +def initialise_database(password:str): + existing_clients = session.query(Client).all() # Check if any clients exist in the database + if not existing_clients: # If no clients exist, create an administrator client + add_client('ADMINISTRATOR', 'ADMINISTRATOR', 'ADMINISTRATOR', 'ADMINISTRATOR', 'ADMINISTRATOR', password) # Add the administrator client + session.commit() + admin_client = session.query(Client).filter_by(name='ADMINISTRATOR').one() # Retrieve the administrator client + admin_client.administrator = 1 # Set the new client as an administrator + session.commit() + return jsonify(f"Database initialised with administrator account with client_id {admin_client.client_id}"), 200 + return jsonify("Database not empty, this function cannot be used."), 400 + +@admin_required +def promote_to_admin(client_id:str): + for client in session.query(Client).all(): + if client.client_id == client_id: + client.administrator = 1 + session.commit() + return f"client_id: {client_id} has been promoted to administrator.", 200 + return f"client_id: {client_id} is not found.", 404 + +@admin_required +def demote_from_admin(client_id:str): + for client in session.query(Client).all(): + if client.client_id == client_id: + client.administrator = 0 + session.commit() + return f"client_id: {client_id} has been demoted from administrator.", 200 + return f"client_id: {client_id} is not found.", 404 \ No newline at end of file diff --git a/test_database.db b/test_database.db index db817c9..fa57505 100644 Binary files a/test_database.db and b/test_database.db differ