continue development

This commit is contained in:
Lucas Mathews
2024-05-29 13:27:40 +02:00
parent 23db2c2864
commit 054099e7f7
12 changed files with 203 additions and 133 deletions

View File

@@ -135,7 +135,7 @@ paths:
'404': '404':
description: client_id not found description: client_id not found
/Client: /Client:
put: post:
tags: tags:
- client - client
summary: Update an existing client summary: Update an existing client

View File

@@ -57,9 +57,6 @@ def display_account_info(account_id):
label_key.grid(row=0, column=i*2, sticky='w', padx=10) label_key.grid(row=0, column=i*2, sticky='w', padx=10)
label_value.grid(row=0, column=i*2+1, sticky='w', padx=10) label_value.grid(row=0, column=i*2+1, sticky='w', padx=10)
############## ##############
### Layout ### ### Layout ###
############## ##############
@@ -87,6 +84,16 @@ display_account_info(account_id)
table_frame = customtkinter.CTkFrame(root) table_frame = customtkinter.CTkFrame(root)
table_frame.pack(fill=tk.BOTH, expand=True) table_frame.pack(fill=tk.BOTH, expand=True)
# Add buttons for adding a new transaction, requesting the OTP, and editing the account details
button_frame = customtkinter.CTkFrame(root)
button_frame.pack(fill=tk.X, pady=10)
add_transaction_button = customtkinter.CTkButton(button_frame, text="Add Transaction", command=add_transaction)
add_transaction_button.grid(row=0, column=0, padx=10)
request_otp_button = customtkinter.CTkButton(button_frame, text="Request OTP", command=request_otp)
request_otp_button.grid(row=0, column=1, padx=10)
edit_account_details_button = customtkinter.CTkButton(button_frame, text="Edit Account Details", command=edit_account_details)
edit_account_details_button.grid(row=0, column=2, padx=10)
# Create the transactions table # Create the transactions table
transactions_table = ttk.Treeview(table_frame, columns=("Transaction ID", "Transaction Type", "Amount", "Timestamp", "Description", "Account ID", "Recipient Account ID"), show="headings") transactions_table = ttk.Treeview(table_frame, columns=("Transaction ID", "Transaction Type", "Amount", "Timestamp", "Description", "Account ID", "Recipient Account ID"), show="headings")
transactions_table.pack(fill=tk.BOTH, expand=True) transactions_table.pack(fill=tk.BOTH, expand=True)

View File

@@ -8,6 +8,6 @@ dark_theme = dark
theme = dark-blue theme = dark-blue
[client] [client]
default_id = 31d90aad default_id = d18e5ae0
default_password = Happymeal1 default_password = Happymeal1

View File

@@ -2,6 +2,7 @@ import requests
from requests.models import Response from requests.models import Response
from config import CONFIG from config import CONFIG
import json import json
from tkinter import messagebox
############## ##############
### System ### ### System ###
@@ -65,9 +66,14 @@ def update_client(client_id, otp_code, email=None, phone_number=None, address=No
params['phone_number'] = phone_number params['phone_number'] = phone_number
if address is not None: if address is not None:
params['address'] = address params['address'] = address
response = requests.put(CONFIG["server"]["url"] + "/Client", cookies=session_data['session_cookie'], params=params) response = requests.post(CONFIG["server"]["url"] + "/Client", cookies=session_data['session_cookie'], params=params)
response.raise_for_status() response.raise_for_status()
return response.json() return response.json()
except requests.exceptions.HTTPError as e:
if response.status_code == 400:
return {'success': False, 'message': "Invalid OTP."}
print(f"HTTPError: {e}")
return {'success': False, 'message': "Could not connect to the server. Please try again later."}
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
print(f"RequestException: {e}") print(f"RequestException: {e}")
return {'success': False, 'message': "Could not connect to the server. Please try again later."} return {'success': False, 'message': "Could not connect to the server. Please try again later."}
@@ -153,10 +159,12 @@ def generate_otp():
try: try:
with open('application\\session_data.json', 'r') as f: with open('application\\session_data.json', 'r') as f:
session_data = json.load(f) session_data = json.load(f)
client_id = session_data['client_id'] client_id = session_data['client_id']
response = requests.post(CONFIG["server"]["url"] + "/OTP/Generate", cookies=session_data['session_cookie'], params={'client_id': client_id}) response = requests.post(f"{CONFIG['server']['url']}/OTP/Generate", cookies=session_data['session_cookie'], params={'client_id': client_id})
response.raise_for_status() if response.status_code == 200:
return response.json() messagebox.showinfo("OTP", "OTP has been sent to your email.")
else:
response.raise_for_status()
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
print(f"RequestException: {e}") print(f"RequestException: {e}")
return {'success': False, 'message': "Could not connect to the server. Please try again later."} messagebox.showerror("Error", f"Could not generate OTP: {e}")

View File

@@ -5,6 +5,7 @@ import os
from config import CONFIG from config import CONFIG
from connection import logout_client, get_client, update_client, get_accounts, format_balance, generate_otp from connection import logout_client, get_client, update_client, get_accounts, format_balance, generate_otp
# Global variables # Global variables
email_entry = None email_entry = None
phone_entry = None phone_entry = None
@@ -31,6 +32,16 @@ def logout():
else: else:
messagebox.showerror("Logout failed", json_response['message']) messagebox.showerror("Logout failed", json_response['message'])
def exit_application():
"""Logs out the client and exits the application."""
response = logout_client()
json_response = response.json()
if json_response['success']:
messagebox.showinfo("Logout", "You have been logged out.")
root.quit()
else:
messagebox.showerror("Logout failed", json_response['message'])
def display_client_info(): def display_client_info():
"""Displays the client's information on the dashboard.""" """Displays the client's information on the dashboard."""
global frame global frame
@@ -70,7 +81,7 @@ def edit_details():
global edit_window, email_entry, phone_entry, address_entry, otp_entry global edit_window, email_entry, phone_entry, address_entry, otp_entry
edit_window = customtkinter.CTkToplevel(root) edit_window = customtkinter.CTkToplevel(root)
edit_window.title("Edit Details") edit_window.title("Edit Details")
edit_window.geometry("300x300") edit_window.geometry("300x350")
edit_window.iconbitmap("application/luxbank.ico") edit_window.iconbitmap("application/luxbank.ico")
edit_window.attributes('-topmost', True) edit_window.attributes('-topmost', True)
@@ -89,16 +100,17 @@ def edit_details():
address_label.pack() address_label.pack()
address_entry.pack() address_entry.pack()
# Add MFA verify button and text box customtkinter.CTkLabel(edit_window, text=" ").pack() # Add space under the address box
mfa_button = customtkinter.CTkButton(edit_window, text="Get OTP Code", command=generate_otp)
mfa_button.pack()
mfa_label = customtkinter.CTkLabel(edit_window, text="OTP Code: ") otp_button = customtkinter.CTkButton(edit_window, text="Get OTP Code", command=generate_otp)
otp_button.pack()
otp_label = customtkinter.CTkLabel(edit_window, text="OTP Code: ")
otp_entry = customtkinter.CTkEntry(edit_window) otp_entry = customtkinter.CTkEntry(edit_window)
mfa_label.pack() otp_label.pack()
otp_entry.pack() otp_entry.pack()
save_button = customtkinter.CTkButton(edit_window, text="Verify MFA and Save", command=save_details) save_button = customtkinter.CTkButton(edit_window, text="Verify OTP and Save", command=save_details)
save_button.pack() save_button.pack()
edit_window.lift() edit_window.lift()
@@ -109,18 +121,33 @@ def save_details():
new_phone = phone_entry.get() if phone_entry.get() != '' else None new_phone = phone_entry.get() if phone_entry.get() != '' else None
new_address = address_entry.get() if address_entry.get() != '' else None new_address = address_entry.get() if address_entry.get() != '' else None
otp_code = otp_entry.get() otp_code = otp_entry.get()
if not otp_code:
messagebox.showerror("Error", "OTP code must be entered.")
return
with open('application\\session_data.json', 'r') as f: with open('application\\session_data.json', 'r') as f:
session_data = json.load(f) session_data = json.load(f)
client_id = session_data['client_id'] client_id = session_data['client_id']
if not messagebox.askyesno("Confirmation", "Are you sure you want to update the details?"): if not messagebox.askyesno("Confirmation", "Are you sure you want to update the details?"):
return return
result = update_client(client_id, otp_code, new_email, new_phone, new_address)
if result['success']: try:
display_client_info() result = update_client(client_id, otp_code, new_email, new_phone, new_address)
else: if result['success']:
messagebox.showerror("Update Failed", result.get('message', 'Unknown error')) display_client_info()
edit_window.destroy() messagebox.showinfo("Success", "Details updated successfully.")
edit_window.destroy()
else:
if result['message'] == "Invalid OTP.":
messagebox.showerror("Error", "MFA details not correct. Please try again.")
else:
messagebox.showerror("Update Failed", result.get('message', 'Unknown error'))
except Exception as e:
messagebox.showerror("Error", f"An error occurred: {e}")
def populate_table(): def populate_table():
"""Populates the accounts table with client accounts.""" """Populates the accounts table with client accounts."""
try: try:
@@ -169,13 +196,21 @@ welcome_label.pack(pady=20)
display_client_info() display_client_info()
# Create a logout button # Create a frame for buttons
logout_button = customtkinter.CTkButton(root, text="Logout", command=logout) button_frame = customtkinter.CTkFrame(root)
logout_button.pack(pady=15) button_frame.pack(pady=15, side='top')
# Create the MFA button # Create the OTP button
mfa_button = customtkinter.CTkButton(root, text="MFA", command=generate_otp) otp_button = customtkinter.CTkButton(button_frame, text="Get OTP Code", command=generate_otp)
mfa_button.pack(pady=15, side='left') otp_button.pack(side='left', padx=5)
# Create the logout button
logout_button = customtkinter.CTkButton(button_frame, text="Logout", command=logout)
logout_button.pack(side='left', padx=5)
# Create the exit button
exit_button = customtkinter.CTkButton(button_frame, text="Exit", command=exit_application)
exit_button.pack(side='left', padx=5)
# Create a frame for the table # Create a frame for the table
table_frame = ttk.Frame(root) table_frame = ttk.Frame(root)

View File

@@ -1 +1 @@
{"session_cookie": {"session": "mMTYW-c_n0BE-l7MENT8A1h2Rg4UUrNRJYl7NvXTcS4"}, "client_id": "31d90aad"} {"session_cookie": {"session": "CjjpiVUxx009emp27lUSxMpJ4Dt1sUi3fV-_VILXFrw"}, "client_id": "d18e5ae0"}

View File

@@ -1,35 +1,47 @@
# Lucas Mathews - Fontys Student ID: 5023572 import smtplib
# Banking System Emailer import ssl
import smtplib, ssl
from config import CONFIG # Import Config
from email.mime.text import MIMEText from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from config import CONFIG
context = ssl.create_default_context() # Create a secure SSL context
email = "l.mathews@student.fontys.nl" # These three lines are for testing purposes class EmailSendingError(Exception):
subject = "Test Email" """Custom exception raised when an error occurs during email sending."""
body = "This is a test email." def __init__(self, message, original_error=None):
super().__init__(message)
self.original_error = original_error
def send_email(receiver_email, subject, body): def send_email(receiver_email, subject, body):
"""Sends an email to the specified receiver email address.""" """Sends an email to the specified receiver email address."""
sender_email = CONFIG["smtp"]["sender_email"] sender_email = CONFIG["smtp"]["sender_email"]
message = MIMEMultipart() # Create a multipart message and set headers message = MIMEMultipart()
message["From"] = f"{CONFIG["smtp"]["sender_name"]} <{CONFIG["smtp"]["sender_email"]}>" message["From"] = f"{CONFIG['smtp']['sender_name']} <{sender_email}>"
message["To"] = receiver_email message["To"] = receiver_email
message["Subject"] = subject message["Subject"] = subject
message.attach(MIMEText(body, "plain")) # Add body to email message.attach(MIMEText(body, "plain"))
text = message.as_string() text = message.as_string()
with smtplib.SMTP_SSL(CONFIG["smtp"]["host"], CONFIG["smtp"]["port"], context=context) as server: context = ssl.create_default_context()
server.login(CONFIG["smtp"]["username"], CONFIG["smtp"]["password"]) try:
server.sendmail(sender_email, receiver_email, text) with smtplib.SMTP_SSL(CONFIG["smtp"]["host"], CONFIG["smtp"]["port"], context=context) as server:
print(f"Email sent to {receiver_email}.") server.login(CONFIG["smtp"]["username"], CONFIG["smtp"]["password"])
server.quit() server.sendmail(sender_email, receiver_email, text)
print(f"Email sent to {receiver_email}.")
except Exception as e:
error_message = f"Failed to send email to {receiver_email}: {e}"
print(error_message)
raise EmailSendingError(error_message)
if __name__ == "__main__": if __name__ == "__main__":
send_email(email, subject, body) email = "l.mathews@student.fontys.nl"
subject = "Test Email"
body = "This is a test email."
try:
send_email(email, subject, body)
except EmailSendingError:
print("Email sending failed.")

View File

@@ -4,6 +4,7 @@
from class_client import Client from class_client import Client
from class_account import Account from class_account import Account
from class_transaction import Transaction from class_transaction import Transaction
from emailer import EmailSendingError # Import the EmailSendingError class to handle email sending errors
from flask import jsonify, session as flask_session # Imports the Flask modules from flask import jsonify, session as flask_session # Imports the Flask modules
import hashlib # For password hashing import hashlib # For password hashing
import datetime # For timestamps import datetime # For timestamps
@@ -133,17 +134,27 @@ def admin_required(f):
return decorated_function return decorated_function
@login_required @login_required
def generate_otp(client_id:str): def generate_otp(client_id: str):
"""Generates a one time password for a client and sends it to their email address. Returns a success message if the OTP is generated and an error message otherwise.""" """Generates a one-time password for a client and sends it to their email address. Returns a success message if the OTP is generated and an error message otherwise."""
current_client_id, is_admin = get_current_client() current_client_id, is_admin = get_current_client()
if not is_admin and client_id != current_client_id: if not is_admin and client_id != current_client_id:
return format_response(False, "You can only generate OTPs for your own client account."), 403 return format_response(False, "You can only generate OTPs for your own client account."), 403
email = get_email(client_id) email = get_email(client_id)
if email: if email:
password = int(random.randint(100000, 999999)) # Generate a 6-digit OTP password = int(random.randint(100000, 999999)) # Generate a 6-digit OTP
send_email(email, "Luxbank One Time Password", f"Your one time password is: {password}"), 200 try:
otps[client_id] = (password, time.time()) # Store the OTP and the current time send_email(email, "Luxbank One Time Password", f"Your one-time password is: {password}")
return format_response(True, "Client not found."), 404 otps[client_id] = (password, time.time()) # Store the OTP and the current time
return format_response(True, "OTP generated and sent successfully."), 200
except EmailSendingError as e:
print(f"Error sending email: {e}")
error_message = "Error sending email. Please try again later."
if e.original_error:
error_message += f" Original error: {str(e.original_error)}"
return format_response(False, error_message), 500
else:
return format_response(False, "Email address not found for the client."), 404
############## ##############
@@ -162,37 +173,25 @@ def get_client(client_id:str):
return format_response(False, "Client not found."), 404 return format_response(False, "Client not found."), 404
@login_required @login_required
def update_client(client_id:str, otp_code:int, **kwargs): def update_client(client_id: str, otp_code: int, **kwargs):
"""Updates a client in the database. If the client is not found, returns an error message.""" """Updates a client in the database. If the client is not found, returns an error message."""
current_client_id, is_admin = get_current_client() current_client_id, is_admin = get_current_client()
if not verify_otp(current_client_id, otp_code): if not verify_otp(current_client_id, otp_code):
return format_response(False, "Invalid OTP."), 405 return format_response(False, "Invalid OTP."), 400 # Changed to 400 Bad Request
if not is_admin and client_id != current_client_id: if not is_admin and client_id != current_client_id:
return format_response(False, "You can only view your own client information."), 403 return format_response(False, "You can only view your own client information."), 403
for client in session.query(Client).all():
if client.client_id == client_id: client = session.query(Client).filter_by(client_id=client_id).first()
name = kwargs.get("name", None) if client:
birthdate = kwargs.get("birthdate", None) for field in ['name', 'birthdate', 'address', 'phone_number', 'email', 'notes']:
address = kwargs.get("address", None) if field in kwargs and kwargs[field] is not None:
phone_number = kwargs.get("phone_number", None) setattr(client, field, kwargs[field])
email = kwargs.get("email", None) session.commit()
notes = kwargs.get("notes", None) return format_response(True, f"Client ID: {client_id} has been updated."), 200
if name:
client.name = name
if birthdate:
client.birthdate = birthdate
if address:
client.address = address
if phone_number:
client.phone_number = phone_number
if email:
client.email = email
if notes:
client.notes = notes
session.commit()
return format_response(True, f"client_id: {client_id} has been updated."), 200
return format_response(False, "Client not found."), 404 return format_response(False, "Client not found."), 404
@login_required @login_required
def change_password(client_id:str, password:str, new_password:str, otp:int): def change_password(client_id:str, password:str, new_password:str, otp:int):
"""Changes the password for a client in the database. If the client is not found, returns an error message.""" """Changes the password for a client in the database. If the client is not found, returns an error message."""

Binary file not shown.

View File

@@ -1,14 +1,7 @@
# Lucas Mathews - Fontys Student ID: 5023572 # Lucas Mathews - Fontys Student ID: 5023572
# Banking System Test Database Generator # Banking System Test Database Generator
# This program generates a test database for the banking system. The database contains 50 clients, each with 2 accounts. Each account has 40 transactions. ADMIN_EMAIL = "lmath56@hotmail.com"
# The first client is an administrator. The password for the administrator account is "Happymeal1". The program uses the Faker library to generate fake
# data for the clients, accounts, and transactions. The random library is used to generate random data for the accounts and transactions. The program
# creates a new SQLite database called test_database.db and writes the test data to the database. The client ID of the administrator account and the
# password for the administrator account.
ADMIN_EMAIL = "lmath56@hotmail.com" # Email address of the administrator account
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
@@ -19,97 +12,113 @@ from class_transaction import Transaction
from faker import Faker from faker import Faker
import random import random
import datetime import datetime
import hashlib import hashlib
import uuid import uuid
from datetime import datetime, timedelta
def generate_hash(): # Creates a hash for a password
def generate_hash():
seed = str(random.random()).encode('utf-8') seed = str(random.random()).encode('utf-8')
return hashlib.sha512(seed).hexdigest() return hashlib.sha512(seed).hexdigest()
def generate_uuid(): # Generates a unique identifier for transactions def generate_uuid():
return str(uuid.uuid4()) return str(uuid.uuid4())
def generate_uuid_short(): # Generates a short uuid for accounts and clients def generate_uuid_short():
return str(uuid.uuid4())[:8] return str(uuid.uuid4())[:8]
def timestamp(): # Returns the current timestamp def current_timestamp():
return (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
engine = create_engine('sqlite:///test_database.db')# Create a new engine for the test database def random_date(start, end):
Base.metadata.create_all(engine) # Create all tables in the test database return start + timedelta(seconds=random.randint(0, int((end - start).total_seconds())))
Session = sessionmaker(bind=engine) # Create a new sessionmaker bound to the test engine
session = Session() # Create a new session
fake = Faker() # Create a Faker instance def timestamp_this_year():
start = datetime(datetime.now().year, 1, 1)
end = datetime(datetime.now().year, 12, 31, 23, 59, 59)
return random_date(start, end).strftime("%Y-%m-%d %H:%M:%S")
all_account_ids = [] # List to store all account IDs def timestamp_this_century():
start = datetime(2000, 1, 1)
end = datetime(2099, 12, 31, 23, 59, 59)
return random_date(start, end).strftime("%Y-%m-%d %H:%M:%S")
for i in range(50): # Generate 50 clients
is_administrator = 1 if i == 0 else 0 # Set the first client as an administrator engine = create_engine('sqlite:///test_database.db')
# Set the password hash for the first account so that the password is "Happymeal1" Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
fake = Faker()
all_account_ids = []
for i in range(50):
is_administrator = 1 if i == 0 else 0
password_hash = "7835062ec36ed529fe22cc63baf3ec18d347dacb21c9801da8ba0848cc18efdf1e51717dd5b1240f7556aca3947aa0722452858be6002c1d46b1f1c311b0e9d8" if i == 0 else generate_hash() password_hash = "7835062ec36ed529fe22cc63baf3ec18d347dacb21c9801da8ba0848cc18efdf1e51717dd5b1240f7556aca3947aa0722452858be6002c1d46b1f1c311b0e9d8" if i == 0 else generate_hash()
client_id = generate_uuid_short() client_id = generate_uuid_short()
all_account_ids.append(client_id) # Add the client ID to the list of account IDs
client = Client( client = Client(
client_id=client_id, client_id=client_id,
name="ADMIN" if i == 0 else fake.name(), name="ADMIN" if i == 0 else fake.name(),
birthdate="ADMIN" if i == 0 else fake.date_of_birth(minimum_age=18, maximum_age=90), birthdate="ADMIN" if i == 0 else timestamp_this_century(),
opening_timestamp=timestamp() if i == 0 else fake.date_this_century(), opening_timestamp=current_timestamp() if i == 0 else timestamp_this_century(),
address="ADMIN" if i == 0 else fake.address(), address="ADMIN" if i == 0 else fake.address(),
phone_number="ADMIN" if i == 0 else fake.phone_number(), phone_number="ADMIN" if i == 0 else fake.phone_number(),
email=ADMIN_EMAIL if i == 0 else fake.email(), email=ADMIN_EMAIL if i == 0 else fake.email(),
administrator=is_administrator, administrator=is_administrator,
hash=password_hash, hash=password_hash,
notes=fake.text(max_nb_chars=50), # Generate fake notes notes=fake.text(max_nb_chars=50),
enabled=1, enabled=1,
accounts=[]) # Empty list for accounts, you can add accounts later) accounts=[]
)
session.add(client) session.add(client)
for j in range(2):# Each client has 2 accounts for j in range(2):
account_id = generate_uuid_short() account_id = generate_uuid_short()
balance = 1000 # Initialize balance to 1000 balance = 1000
for k in range(40): # Each account has 40 transactions
if not all_account_ids: # Skip creating a transaction if there are no accounts yet
continue
for k in range(40):
transaction_type = random.choice(['Deposit', 'Withdrawal']) transaction_type = random.choice(['Deposit', 'Withdrawal'])
amount = random.randint(1, 200) amount = random.randint(1, 200)
if transaction_type == 'Withdrawal' and balance - amount < 0: # Skip withdrawal if it would make balance negative if transaction_type == 'Withdrawal' and balance - amount < 0:
continue continue
if transaction_type == 'Deposit': # Update balance based on transaction type if transaction_type == 'Deposit':
balance += amount balance += amount
elif transaction_type == 'Withdrawal': else:
balance -= amount balance -= amount
transaction = Transaction( transaction = Transaction(
transaction_id=generate_uuid(), transaction_id=generate_uuid(),
account_id=account_id, account_id=account_id,
recipient_account_id=random.choice(all_account_ids), recipient_account_id=random.choice(all_account_ids) if all_account_ids else account_id,
transaction_type=transaction_type, transaction_type=transaction_type,
amount=amount, amount=amount,
timestamp=fake.date_this_year(), timestamp=timestamp_this_year(),
description=fake.text(max_nb_chars=50) description=fake.text(max_nb_chars=20)
) )
session.add(transaction) session.add(transaction)
account = Account( account = Account(
account_id=account_id, account_id=account_id,
client_id=client_id, client_id=client_id,
description=fake.text(max_nb_chars=200), description=fake.text(max_nb_chars=20),
open_timestamp=fake.date_this_century(), open_timestamp=timestamp_this_year(),
account_type=random.choice(['Spending', 'Savings']), account_type=random.choice(['Spending', 'Savings']),
balance=balance, # Set balance to calculated balance balance=balance,
enabled=1, enabled=1,
notes=fake.text(max_nb_chars=50), notes=fake.text(max_nb_chars=50),
transactions=[]) transactions=[]
)
session.add(account) session.add(account)
all_account_ids.append(account_id) all_account_ids.append(account_id)
session.commit() # Commit the session to write the test data to the database session.commit()
print(f"The client_id of the administrator account of this test database is: {all_account_ids[0]}. The password is: Happymeal1") # Retrieve the client_id of the administrator account from the session
admin_client_id = session.query(Client.client_id).filter(Client.administrator == 1).first()[0]
session.close() # Close the session # Print the client_id of the administrator account
print(f"The client_id of the administrator account of this test database is: {admin_client_id}. The password is: Happymeal1")
session.close()