""" Имитация функций банка Условия задачи: Проект онлайн - банк(В стадии разработки) Необходимо создать "онлайн" банк, у которого будут реализованы следующие функции. Разумеется, мы не создаем полноценный онлайн банк, это просто имитация. 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