Account creation works
This commit is contained in:
parent
35a9e64a10
commit
e28e1027d0
46
poetry.lock
generated
46
poetry.lock
generated
@ -135,6 +135,7 @@ files = [
|
|||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
mypy_extensions = ">=1.0.0"
|
mypy_extensions = ">=1.0.0"
|
||||||
|
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||||
typing_extensions = ">=4.6.0"
|
typing_extensions = ">=4.6.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@ -265,6 +266,47 @@ postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"]
|
|||||||
pymysql = ["pymysql"]
|
pymysql = ["pymysql"]
|
||||||
sqlcipher = ["sqlcipher3_binary"]
|
sqlcipher = ["sqlcipher3_binary"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli"
|
||||||
|
version = "2.2.1"
|
||||||
|
description = "A lil' TOML parser"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
|
||||||
|
{file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
|
||||||
|
{file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
|
||||||
|
{file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
|
||||||
|
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
|
||||||
|
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
version = "4.12.2"
|
version = "4.12.2"
|
||||||
@ -278,5 +320,5 @@ files = [
|
|||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.12"
|
python-versions = "^3.8"
|
||||||
content-hash = "c924c9033c266a86318eb310c7ef433b346d0ad4ff1574e44f7c8c664653106f"
|
content-hash = "822be0591477b901b0d6f8a34048f570227733ebf8eda1cae6a079ab2f5a1415"
|
||||||
|
@ -6,7 +6,7 @@ authors = ["Thastertyn <thastertyn@thastertyn.xyz>"]
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.6"
|
python = "^3.8"
|
||||||
sqlalchemy = "^2.0.37"
|
sqlalchemy = "^2.0.37"
|
||||||
python-dotenv = "^1.0.1"
|
python-dotenv = "^1.0.1"
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ class BankNode():
|
|||||||
client_socket, address = socket_server.accept()
|
client_socket, address = socket_server.accept()
|
||||||
self.logger.info("%s connected", address[0])
|
self.logger.info("%s connected", address[0])
|
||||||
|
|
||||||
process = BankWorker(client_socket, address, self.config.to_dict())
|
process = BankWorker(client_socket, address, self.config)
|
||||||
process.start()
|
process.start()
|
||||||
|
|
||||||
def exit_with_error(self):
|
def exit_with_error(self):
|
||||||
|
@ -3,6 +3,7 @@ from typing import Dict, Callable
|
|||||||
|
|
||||||
from core import Request, Response
|
from core import Request, Response
|
||||||
from core.exceptions import BankNodeError
|
from core.exceptions import BankNodeError
|
||||||
|
from database.exceptions import DatabaseError
|
||||||
|
|
||||||
from bank_protocol.commands import (account_balance,
|
from bank_protocol.commands import (account_balance,
|
||||||
account_create,
|
account_create,
|
||||||
@ -36,7 +37,8 @@ class CommandHandler:
|
|||||||
raise BankNodeError(f"Unknown command {request.command_code}")
|
raise BankNodeError(f"Unknown command {request.command_code}")
|
||||||
|
|
||||||
command = self.registered_commands[request.command_code]
|
command = self.registered_commands[request.command_code]
|
||||||
|
try:
|
||||||
response = command(request, self.config)
|
response = command(request, self.config)
|
||||||
|
|
||||||
return f"{request.command_code} {response}"
|
return f"{request.command_code} {response}"
|
||||||
|
except DatabaseError as e:
|
||||||
|
return f"ER {e.message}"
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
from core.request import Request
|
from core import Request, Response, BankNodeConfig
|
||||||
|
from bank_protocol.exceptions import InvalidRequest
|
||||||
|
from services.account_service import create_account
|
||||||
|
|
||||||
|
|
||||||
|
def account_create(request: Request, config: BankNodeConfig) -> Response:
|
||||||
|
if request.body is not None:
|
||||||
|
raise InvalidRequest("Incorrect usage")
|
||||||
|
|
||||||
|
account_number = create_account()
|
||||||
|
|
||||||
|
return f"{account_number}/{config.ip}"
|
||||||
|
|
||||||
def account_create(request: Request):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["account_create"]
|
__all__ = ["account_create"]
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from core import Request
|
from core import Request, BankNodeConfig
|
||||||
from bank_protocol.exceptions import InvalidRequest
|
from bank_protocol.exceptions import InvalidRequest
|
||||||
|
|
||||||
def account_deposit(request: Request):
|
|
||||||
|
def account_deposit(request: Request, config: BankNodeConfig):
|
||||||
split_body = request.body.split("/")
|
split_body = request.body.split("/")
|
||||||
split_ip = split_body[1].split(" ")
|
split_ip = split_body[1].split(" ")
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class DatabaseManager():
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def get_session(cls) -> Generator[Session]:
|
def get_session(cls) -> Generator[Session, None, None]:
|
||||||
session = cls._instance.Session()
|
session = cls._instance.Session()
|
||||||
try:
|
try:
|
||||||
yield session
|
yield session
|
||||||
|
@ -37,4 +37,16 @@ class OutOfAccountSpaceError(DatabaseError):
|
|||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["DatabaseError", "DatabaseConnectionError", "DuplicateEntryError"]
|
class InsufficientBalance(DatabaseError):
|
||||||
|
def __init__(self, message: str):
|
||||||
|
super().__init__(message)
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidOperation(DatabaseError):
|
||||||
|
def __init__(self, message: str):
|
||||||
|
super().__init__(message)
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["DatabaseError", "DatabaseConnectionError", "DuplicateEntryError", "InsufficientBalance", "OutOfAccountSpaceError", "NonexistentAccountError", "EmptyDatabaseConfigError", "InvalidOperation"]
|
||||||
|
@ -5,7 +5,7 @@ from .base_model import Base
|
|||||||
|
|
||||||
class Account(Base):
|
class Account(Base):
|
||||||
__tablename__ = 'account'
|
__tablename__ = 'account'
|
||||||
__table_args__ = (CheckConstraint('account_number > 10000 and account_number <= 99999'),)
|
__table_args__ = (CheckConstraint('account_number >= 10000 and account_number <= 99999'),)
|
||||||
|
|
||||||
account_number = Column(Integer, nullable=False, primary_key=True)
|
account_number = Column(Integer, nullable=False, primary_key=True)
|
||||||
balance = Column(Integer)
|
balance = Column(Integer)
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
from sqlalchemy import func
|
|
||||||
|
|
||||||
from models import Account
|
|
||||||
from database import DatabaseManager
|
|
||||||
from database.exceptions import OutOfAccountSpaceError, NonexistentAccountError
|
|
||||||
from utils.constants import MIN_ACCOUNT_NUMBER, MAX_ACCOUNT_NUMBER
|
|
||||||
|
|
||||||
|
|
||||||
def get_next_id() -> int:
|
|
||||||
with DatabaseManager.get_session() as session:
|
|
||||||
new_id = session.query(func.max(Account.account_number)).scalar()
|
|
||||||
new_id = new_id if new_id is not None else MIN_ACCOUNT_NUMBER
|
|
||||||
|
|
||||||
if new_id > MAX_ACCOUNT_NUMBER:
|
|
||||||
raise OutOfAccountSpaceError("Too many users already exist, cannot open new account")
|
|
||||||
|
|
||||||
return new_id
|
|
||||||
|
|
||||||
|
|
||||||
def create_account() -> int:
|
|
||||||
new_id = get_next_id()
|
|
||||||
|
|
||||||
with DatabaseManager.get_session() as session:
|
|
||||||
new_account = Account(account_number=new_id, balance=0)
|
|
||||||
session.add(new_account)
|
|
||||||
session.commit()
|
|
||||||
return new_id
|
|
||||||
|
|
||||||
|
|
||||||
def get_account_balance(account_number: int) -> int:
|
|
||||||
with DatabaseManager.get_session() as session:
|
|
||||||
account: Account = session.query(Account).where(Account.account_number == account_number).one_or_none()
|
|
||||||
if account is NotImplemented:
|
|
||||||
raise NonexistentAccountError(f"Account with number {account_number} doesn't exist")
|
|
||||||
|
|
||||||
return account.balance
|
|
||||||
|
|
||||||
def withdraw_from_account():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def deposit_into_account():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def delete_account():
|
|
||||||
pass
|
|
73
src/services/account_service.py
Normal file
73
src/services/account_service.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
from sqlalchemy import func
|
||||||
|
|
||||||
|
from models import Account
|
||||||
|
from database import DatabaseManager
|
||||||
|
from database.exceptions import OutOfAccountSpaceError, NonexistentAccountError, InsufficientBalance, InvalidOperation
|
||||||
|
from utils.constants import MIN_ACCOUNT_NUMBER, MAX_ACCOUNT_NUMBER
|
||||||
|
|
||||||
|
|
||||||
|
def get_next_id() -> int:
|
||||||
|
with DatabaseManager.get_session() as session:
|
||||||
|
current_max_id = session.query(func.max(Account.account_number)).scalar()
|
||||||
|
current_max_id = current_max_id + 1 if current_max_id is not None else MIN_ACCOUNT_NUMBER
|
||||||
|
|
||||||
|
if current_max_id > MAX_ACCOUNT_NUMBER:
|
||||||
|
raise OutOfAccountSpaceError("Too many users already exist, cannot open new account")
|
||||||
|
|
||||||
|
return current_max_id
|
||||||
|
|
||||||
|
|
||||||
|
def create_account() -> int:
|
||||||
|
new_id = get_next_id()
|
||||||
|
|
||||||
|
with DatabaseManager.get_session() as session:
|
||||||
|
new_account = Account(account_number=new_id, balance=0)
|
||||||
|
session.add(new_account)
|
||||||
|
session.commit()
|
||||||
|
return new_id
|
||||||
|
|
||||||
|
|
||||||
|
def get_account_balance(account_number: int) -> int:
|
||||||
|
with DatabaseManager.get_session() as session:
|
||||||
|
account: Account = session.query(Account).where(Account.account_number == account_number).one_or_none()
|
||||||
|
if account is None:
|
||||||
|
raise NonexistentAccountError(f"Account with number {account_number} doesn't exist")
|
||||||
|
|
||||||
|
return account.balance
|
||||||
|
|
||||||
|
|
||||||
|
def withdraw_from_account(account_number: int, amount: int):
|
||||||
|
modify_balance(account_number, amount, True)
|
||||||
|
|
||||||
|
|
||||||
|
def deposit_into_account(account_number: int, amount: int):
|
||||||
|
modify_balance(account_number, amount, False)
|
||||||
|
|
||||||
|
|
||||||
|
def modify_balance(account_number: int, amount: int, subtract: bool):
|
||||||
|
with DatabaseManager.get_session() as session:
|
||||||
|
account: Account = session.query(Account).where(Account.account_number == account_number).one_or_none()
|
||||||
|
if account is None:
|
||||||
|
raise NonexistentAccountError(f"Account with number {account_number} doesn't exist")
|
||||||
|
|
||||||
|
if subtract:
|
||||||
|
account.balance += amount
|
||||||
|
else:
|
||||||
|
if account.balance - amount < 0:
|
||||||
|
raise InsufficientBalance("Not enough funds on account to withdraw this much")
|
||||||
|
account.balance -= amount
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_account(account_number: int):
|
||||||
|
with DatabaseManager.get_session() as session:
|
||||||
|
account: Account = session.query(Account).where(Account.account_number == account_number).one_or_none()
|
||||||
|
if account is None:
|
||||||
|
raise NonexistentAccountError(f"Account with number {account_number} doesn't exist")
|
||||||
|
|
||||||
|
if account.balance > 0:
|
||||||
|
raise InvalidOperation("Cannot delete an account with leftover funds")
|
||||||
|
|
||||||
|
session.delete(account)
|
||||||
|
session.commit()
|
Loading…
x
Reference in New Issue
Block a user