bank: ckeckpoint
This commit is contained in:
parent
aa7ea9e512
commit
781dbaf709
280
bank.py
Normal file
280
bank.py
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
"""
|
||||||
|
Имитация функций банка
|
||||||
|
|
||||||
|
Условия задачи:
|
||||||
|
Проект онлайн - банк(В стадии разработки)
|
||||||
|
|
||||||
|
Необходимо создать "онлайн" банк, у которого будут реализованы следующие функции. Разумеется, мы не создаем полноценный онлайн банк, это просто имитация.
|
||||||
|
1. Регистрация
|
||||||
|
2. Вход (Необходимо сделать, чтобы у каждого пользователя программы была возможность
|
||||||
|
После входа в случае если это происходит днем нужно вывести Добрый день!, если это происходит вечером, нужно вывести добрый вечер!, если ночью -- то нужно вывести Доброй ночи
|
||||||
|
3. Открытие счета
|
||||||
|
4. Пополнение(вводя данные кредитной карты)
|
||||||
|
При вводе кредитной карты необходимо проверять правильность ее ввода.
|
||||||
|
5. Проверка идентификации пользователя (Пользователь при регистрации вводит свой e-mail, туда отправляется письмо со случайной цифрой, эту цифру необходимо ввести в программу. Если число сгенерированное совпадает, то мы говорим, что человек прошел верификацию
|
||||||
|
6. Оплатить мобильный телефон (просто с телефона снимается определенная сумма денег)
|
||||||
|
7. Показать рейтинг
|
||||||
|
8. Сделать викторину(За каждый правильный ответ пользователю начисляется балл в рейтинг)
|
||||||
|
9. Вывести на экран
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os.path
|
||||||
|
from getpass import getpass
|
||||||
|
from dataclasses import dataclass, field, asdict
|
||||||
|
import hashlib
|
||||||
|
import uuid
|
||||||
|
import hmac
|
||||||
|
import datetime
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def get_hello_hour():
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
return ["Доброй ночи", "Доброе утро", "Добрый день", "Добрый вечер"][now.hour // 6]
|
||||||
|
|
||||||
|
|
||||||
|
def validate_credit_card(card_number: str) -> bool:
|
||||||
|
card_number = [int(num) for num in card_number]
|
||||||
|
checkDigit = card_number.pop(-1)
|
||||||
|
card_number.reverse()
|
||||||
|
card_number = [
|
||||||
|
num * 2 if idx % 2 == 0 else num for idx, num in enumerate(card_number)
|
||||||
|
]
|
||||||
|
card_number = [
|
||||||
|
num - 9 if idx % 2 == 0 and num > 9 else num
|
||||||
|
for idx, num in enumerate(card_number)
|
||||||
|
]
|
||||||
|
card_number.append(checkDigit)
|
||||||
|
checkSum = sum(card_number)
|
||||||
|
return checkSum % 10 == 0
|
||||||
|
|
||||||
|
|
||||||
|
class Singleton(type):
|
||||||
|
_instances = {}
|
||||||
|
|
||||||
|
def __call__(cls, *args, **kwargs):
|
||||||
|
if cls not in cls._instances:
|
||||||
|
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
||||||
|
return cls._instances[cls]
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleDataBase(metaclass=Singleton):
|
||||||
|
__FILENAME = "bank.json"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
if os.path.isfile(self.__class__.__FILENAME):
|
||||||
|
with open(self.__class__.__FILENAME, "r", encoding="utf-8") as f:
|
||||||
|
self.data = json.load(f)
|
||||||
|
else:
|
||||||
|
self.data = {"users": {}, "accounts": {}, "rating": {}}
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
with open(self.__class__.__FILENAME, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(self.data, f)
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return self.data[attr]
|
||||||
|
|
||||||
|
def __setattr__(self, attr, value):
|
||||||
|
self.data[attr] = value
|
||||||
|
|
||||||
|
def __delattr__(self, attr):
|
||||||
|
del self.data[attr]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class User:
|
||||||
|
name: str
|
||||||
|
fio: str
|
||||||
|
email: str
|
||||||
|
verification_code: int
|
||||||
|
is_verifyed: bool = field(init=False)
|
||||||
|
salt: str = field(init=False)
|
||||||
|
hash: str = field(init=False)
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
self.hash = ""
|
||||||
|
self.salt = ""
|
||||||
|
self.is_verifyed = False
|
||||||
|
|
||||||
|
def set_password(self, password):
|
||||||
|
self.salt = uuid.uuid4().hex
|
||||||
|
self.hash = hashlib.sha512((password + self.salt).encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
|
def authenticate(self, password):
|
||||||
|
hash = hashlib.sha512((password + self.salt).encode("utf-8")).digest()
|
||||||
|
return hmac.compare_digest(hash, bytes.fromhex(self.hash))
|
||||||
|
|
||||||
|
def email_verification(self, code):
|
||||||
|
res = self.verification_code == code
|
||||||
|
if not self.is_verifyed:
|
||||||
|
self.is_verifyed = res
|
||||||
|
return self.is_verifyed
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
users = Users()
|
||||||
|
users.save_user(self)
|
||||||
|
|
||||||
|
|
||||||
|
class Users(metaclass=Singleton):
|
||||||
|
def __init__(self):
|
||||||
|
self.db = SimpleDataBase()
|
||||||
|
|
||||||
|
def get_user(self, name):
|
||||||
|
return self.db.users.get(name)
|
||||||
|
|
||||||
|
def save_user(self, user):
|
||||||
|
self.db.users[user.name] = asdict(user)
|
||||||
|
|
||||||
|
def add_user(self, name, fio, email, verification_code, password):
|
||||||
|
if self.get_user(name) is not None:
|
||||||
|
return False
|
||||||
|
user = User(name, fio, email, verification_code)
|
||||||
|
user.set_password(password)
|
||||||
|
self.save_user(user)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def authenticate(self, name, password):
|
||||||
|
user = self.get_user(name)
|
||||||
|
if user is None:
|
||||||
|
return False
|
||||||
|
return user.authenticate(password)
|
||||||
|
|
||||||
|
|
||||||
|
def fake_email_send(email, code):
|
||||||
|
with open(email, "w", encoding="utf-8") as f:
|
||||||
|
print(f"Ваш код: {code}", file=f)
|
||||||
|
|
||||||
|
|
||||||
|
def registration():
|
||||||
|
print(f"{get_hello_hour()}! Давайте Вас зарегистрируем!")
|
||||||
|
fio = input("Ваше ФИО: ")
|
||||||
|
name = input("Ваш логин: ")
|
||||||
|
email = input("Ваш email: ")
|
||||||
|
verification_code = random.randint(0, 9)
|
||||||
|
password = getpass("Введите пароль: ")
|
||||||
|
# TODO: валидация данных и доп.вопросы
|
||||||
|
users = Users()
|
||||||
|
ok = users.add_user(name, fio, email, verification_code, password)
|
||||||
|
if ok:
|
||||||
|
print("Регистрация успешна, спасибо!")
|
||||||
|
fake_email_send(email, verification_code)
|
||||||
|
print(
|
||||||
|
"На Ваш email отправлен код идентификации (создан файл в текущей папке с именем=email)"
|
||||||
|
)
|
||||||
|
users.db.commit()
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
print("Ошибка, выберите другой логин!")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def login():
|
||||||
|
print(f"{get_hello_hour()}! Добро пожаловать в систему банка!")
|
||||||
|
name = input("Ваш логин: ")
|
||||||
|
password = getpass("Введите пароль: ")
|
||||||
|
# TODO: валидация данных и доп.вопросы
|
||||||
|
users = Users()
|
||||||
|
user = users.authenticate(name, password)
|
||||||
|
if user:
|
||||||
|
print("Вы успешно вошли в систему!")
|
||||||
|
else:
|
||||||
|
print("Ошибка: Неправильный логин или пароль!")
|
||||||
|
exit(1)
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
def user_verification():
|
||||||
|
user = login()
|
||||||
|
users = Users()
|
||||||
|
code = int(input("Введите код идентификации: "))
|
||||||
|
res = user.email_verification(code)
|
||||||
|
if res:
|
||||||
|
print("Вы успешно идентивицированы!")
|
||||||
|
users.db.commit()
|
||||||
|
else:
|
||||||
|
print("К сожалению код не подходит!")
|
||||||
|
if "да" == input("Введите да, чтобы отправить новый код: "):
|
||||||
|
user.verification_code = random.randint(0, 9)
|
||||||
|
fake_email_send(user.email, user.verification_code)
|
||||||
|
user.save()
|
||||||
|
print(
|
||||||
|
"На Ваш email отправлен код идентификации (создан файл в текущей папке с именем=email)"
|
||||||
|
)
|
||||||
|
users.db.commit()
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def open_account():
|
||||||
|
user = login()
|
||||||
|
db = SimpleDataBase()
|
||||||
|
if user.name in db.accounts:
|
||||||
|
print("Счет уже открыт")
|
||||||
|
exit(1)
|
||||||
|
db.accounts[user.name] = 0
|
||||||
|
db.commit()
|
||||||
|
print("Счет успешно открыт")
|
||||||
|
|
||||||
|
|
||||||
|
def print_account_balance():
|
||||||
|
user = login()
|
||||||
|
db = SimpleDataBase()
|
||||||
|
if user.name not in db.accounts:
|
||||||
|
print("Счет не открыт")
|
||||||
|
exit(1)
|
||||||
|
balance = round(db.accounts[user.name] / 100, 2)
|
||||||
|
print(f"На балансе: {balance} руб.")
|
||||||
|
|
||||||
|
|
||||||
|
def addition_from_card():
|
||||||
|
user = login()
|
||||||
|
db = SimpleDataBase()
|
||||||
|
|
||||||
|
if user.name not in db.accounts:
|
||||||
|
print("Сначала нужно открыть счет")
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
is_valid = False
|
||||||
|
while not is_valid:
|
||||||
|
card = input("Введите номер карты: ")
|
||||||
|
is_valid = validate_credit_card(card)
|
||||||
|
if not is_valid:
|
||||||
|
if "да" != input("Введите да, чтобы попытаться ещё раз: "):
|
||||||
|
break
|
||||||
|
if not is_valid:
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
amount = float(input("Введите сумму пополнения: "))
|
||||||
|
# рубли и копейки комбинируем в int, чтобы избежать проблем с float
|
||||||
|
amount = int(amount * 100)
|
||||||
|
db.accounts[user.name] += amount
|
||||||
|
db.commit()
|
||||||
|
print("Баланс пополнен успешно")
|
||||||
|
|
||||||
|
|
||||||
|
def payment_for_phone():
|
||||||
|
user = login()
|
||||||
|
db = SimpleDataBase()
|
||||||
|
|
||||||
|
if user.name not in db.accounts:
|
||||||
|
print("Сначала нужно открыть счет")
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
phone = input("Введите номер телефона: ")
|
||||||
|
# TODO: Валидация номера телефона
|
||||||
|
|
||||||
|
amount = float(input("Введите сумму платежа: "))
|
||||||
|
# рубли и копейки комбинируем в int, чтобы избежать проблем с float
|
||||||
|
amount = int(amount * 100)
|
||||||
|
db.accounts[user.name] -= amount
|
||||||
|
db.commit()
|
||||||
|
print("Платеж выполнен успешно, деньги (типа) отправлены на номер", phone)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: пункт 7
|
||||||
|
# TODO: пункт 8
|
||||||
|
# TODO: пункт 9
|
||||||
|
# TODO: main
|
Loading…
Reference in New Issue
Block a user