From e9cca1d05313f7feacf0c4026f4d95aa4d889f2d Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 27 Jan 2024 01:45:24 +0300 Subject: [PATCH] + bank.py --- bank.py | 290 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 257 insertions(+), 33 deletions(-) diff --git a/bank.py b/bank.py index 7b83dcd..3060e4a 100644 --- a/bank.py +++ b/bank.py @@ -1,7 +1,8 @@ -""" - Имитация функций банка +# Имитация функций банка +# задача: https://stepik.org/lesson/967334/step/7?unit=973876 +# решение: https://gitea.b4tman.ru/temp/py_stepik/src/branch/master/bank.py - Условия задачи: +""" Проект онлайн - банк(В стадии разработки) Необходимо создать "онлайн" банк, у которого будут реализованы следующие функции. Разумеется, мы не создаем полноценный онлайн банк, это просто имитация. @@ -29,6 +30,9 @@ import datetime import random +session = {} + + def get_hello_hour(): now = datetime.datetime.now() return ["Доброй ночи", "Доброе утро", "Добрый день", "Добрый вечер"][now.hour // 6] @@ -73,13 +77,23 @@ class SimpleDataBase(metaclass=Singleton): with open(self.__class__.__FILENAME, "w", encoding="utf-8") as f: json.dump(self.data, f) + @staticmethod + def _is_data(attr): + return "data" == attr + def __getattr__(self, attr): + if self.__class__._is_data(attr): + return super().__getattr__(attr) return self.data[attr] def __setattr__(self, attr, value): + if self.__class__._is_data(attr): + return super().__setattr__(attr, value) self.data[attr] = value def __delattr__(self, attr): + if self.__class__._is_data(attr): + return super().__delattr__(attr) del self.data[attr] @@ -98,15 +112,15 @@ class User: self.salt = "" self.is_verifyed = False - def set_password(self, password): + def set_password(self, password: str): self.salt = uuid.uuid4().hex self.hash = hashlib.sha512((password + self.salt).encode("utf-8")).hexdigest() - def authenticate(self, password): + def authenticate(self, password: str) -> bool: hash = hashlib.sha512((password + self.salt).encode("utf-8")).digest() return hmac.compare_digest(hash, bytes.fromhex(self.hash)) - def email_verification(self, code): + def email_verification(self, code: int) -> bool: res = self.verification_code == code if not self.is_verifyed: self.is_verifyed = res @@ -116,18 +130,28 @@ class User: users = Users() users.save_user(self) + @classmethod + def from_dict(cls, data: dict): + user = cls(*(data[k] for k in "name fio email verification_code".split())) + for k in "is_verifyed salt hash".split(): + setattr(user, k, data[k]) + return user + class Users(metaclass=Singleton): def __init__(self): self.db = SimpleDataBase() - def get_user(self, name): - return self.db.users.get(name) + def get_user(self, name: str) -> User: + data = self.db.users.get(name) + return data and User.from_dict(data) - def save_user(self, user): + def save_user(self, user: User): self.db.users[user.name] = asdict(user) - def add_user(self, name, fio, email, verification_code, password): + def add_user( + self, name: str, fio: str, email: str, verification_code: int, password: str + ) -> bool: if self.get_user(name) is not None: return False user = User(name, fio, email, verification_code) @@ -135,11 +159,11 @@ class Users(metaclass=Singleton): self.save_user(user) return True - def authenticate(self, name, password): + def authenticate(self, name: str, password: str) -> User | None: user = self.get_user(name) if user is None: return False - return user.authenticate(password) + return user.authenticate(password) and user or None def fake_email_send(email, code): @@ -148,6 +172,8 @@ def fake_email_send(email, code): def registration(): + """Регистрация""" + print(f"{get_hello_hour()}! Давайте Вас зарегистрируем!") fio = input("Ваше ФИО: ") name = input("Ваш логин: ") @@ -164,13 +190,19 @@ def registration(): "На Ваш email отправлен код идентификации (создан файл в текущей папке с именем=email)" ) users.db.commit() - exit(0) + + session["user"] = users.get_user(name) else: print("Ошибка, выберите другой логин!") - exit(1) -def login(): +def login() -> User | None: + """Вход""" + + if "user" in session: + print(f"Вы уже вошли в систему, {session['user'].fio}!") + return session["user"] + print(f"{get_hello_hour()}! Добро пожаловать в систему банка!") name = input("Ваш логин: ") password = getpass("Введите пароль: ") @@ -178,20 +210,42 @@ def login(): users = Users() user = users.authenticate(name, password) if user: - print("Вы успешно вошли в систему!") + print(f"Вы успешно вошли в систему, {user.fio}!") else: print("Ошибка: Неправильный логин или пароль!") - exit(1) + return None + session["user"] = user return user +def logout(): + """Выход пользователя""" + + if "user" not in session: + print("Для того чтобы выйти из системы, сначала нужно в неё войти :)") + return + + user = session["user"] + del session["user"] + print(f"До новых встреч, {user.fio}!") + + def user_verification(): + """Идентификация пользователя""" + user = login() + if user is None: + return + + if user.is_verifyed: + print("Вы уже идентифцированы!") + return + users = Users() code = int(input("Введите код идентификации: ")) res = user.email_verification(code) if res: - print("Вы успешно идентивицированы!") + print("Вы успешно идентифицированы!") users.db.commit() else: print("К сожалению код не подходит!") @@ -200,52 +254,82 @@ def user_verification(): fake_email_send(user.email, user.verification_code) user.save() print( - "На Ваш email отправлен код идентификации (создан файл в текущей папке с именем=email)" + f"На Ваш email отправлен код идентификации!\n\t(создан файл в текущей папке с именем={user.email})" ) users.db.commit() - exit(0) else: - exit(1) + print("Выход") def open_account(): + """Открытие счета""" + user = login() + if user is None: + return + db = SimpleDataBase() if user.name in db.accounts: print("Счет уже открыт") - exit(1) + return db.accounts[user.name] = 0 db.commit() print("Счет успешно открыт") -def print_account_balance(): +def print_account_details(): + """Информация о пользователе""" + user = login() + if user is None: + return + + print("\n - - - ") + print("Ваше ФИО:", user.fio) + print("Ваш email:", user.email) + print( + "Ваш статус:", user.is_verifyed and "Идентифицирован" or "Ожидает идентификации" + ) + db = SimpleDataBase() if user.name not in db.accounts: print("Счет не открыт") - exit(1) - balance = round(db.accounts[user.name] / 100, 2) - print(f"На балансе: {balance} руб.") + else: + balance = round(db.accounts[user.name] / 100, 2) + print(f"На балансе: {balance} руб.") + + if user.name not in db.rating: + print("У Вас ещё нет рейтинга") + else: + print(f"Ваш рейтинг: {db.rating[user.name]} баллов") + + print("\n - - - ") def addition_from_card(): + """Пополнение баланса с карты""" + user = login() + if user is None: + return + db = SimpleDataBase() if user.name not in db.accounts: print("Сначала нужно открыть счет") - exit(2) + return is_valid = False while not is_valid: card = input("Введите номер карты: ") is_valid = validate_credit_card(card) if not is_valid: + print("Номер не правильный") if "да" != input("Введите да, чтобы попытаться ещё раз: "): break if not is_valid: - exit(1) + print("Выход") + return amount = float(input("Введите сумму пополнения: ")) # рубли и копейки комбинируем в int, чтобы избежать проблем с float @@ -256,12 +340,17 @@ def addition_from_card(): def payment_for_phone(): + """Оплата мобильного телефона""" + user = login() + if user is None: + return + db = SimpleDataBase() if user.name not in db.accounts: print("Сначала нужно открыть счет") - exit(2) + return phone = input("Введите номер телефона: ") # TODO: Валидация номера телефона @@ -274,7 +363,142 @@ def payment_for_phone(): print("Платеж выполнен успешно, деньги (типа) отправлены на номер", phone) -# TODO: пункт 7 -# TODO: пункт 8 -# TODO: пункт 9 -# TODO: main +def quiz(): + """Рейтинговая викторина""" + + print(' (тема: "Финансовая грамотность")') + questions = [ + ( + """Финансовую защиту благосостояния семьи обеспечивает капитал: + а) резервный + б) текущий + в) инвестиционный""", + "а", + ), + ( + """В соответствии с законом о страховании вкладчик получит право на возмещение по своим вкладам в банке в случае: + а) потери доверия к банку у населения + б) отзыва у банка лицензии + в) повышения инфляции""", + "б", + ), + ( + """Инфляция: + а) повышение заработной платы бюджетникам + б) повышение покупательной способности денег + в) снижение покупательной способности денег""", + "в", + ), + ( + """Кредит, выдаваемый под залог объекта, который приобретается (земельный участок, дом, квартира), называется: + а) ипотечный + б) потребительский + в) целевой""", + "а", + ), + ( + """Счет до востребования с минимальной процентной ставкой, то есть текущий счет, открывается для карты: + а) кредитной + б) дебетовой с овердрафтом + в) дебетовой""", + "в", + ), + ( + """Фондовый рынок — это место, где: + а) продаются и покупаются строительные материалы + б) продаются и покупаются ценные бумаги + в) продаются и покупаются продукты питания""", + "б", + ), + ( + """Биржа — это место, где: + а) продаются и покупаются автомобили + б) продаются и покупаются ценные бумаги + в) место заключения сделок между покупателями и продавцами""", + "в", + ), + ( + """Страховые выплаты компенсируются в случае: + а) материального ущерба + б) морального ущерба + в) желания страхователя получить прибыль""", + "а", + ), + ( + """Выплачиваемая нынешним пенсионерам и формируемая пенсионерам будущим трудовая пенсия по старости, выплачиваемая государством: + а) добавочная + б) второстепенная + в) базовая""", + "в", + ), + ( + """Выплачиваемая нынешним пенсионерам и формируемая пенсионерам будущим трудовая пенсия по старости, выплачиваемая государством: + а) главная + б) накопительная + в) дополнительная""", + "б", + ), + ] + + user = login() + if user is None: + return + + db = SimpleDataBase() + + if user.name in db.rating: + print(f"Ваш текущий рейтинг: {db.rating[user.name]} баллов") + if "выход" == input("Введите 'выход', для того чтобы выйти из тестирования: "): + return + + score = 0 + random.shuffle(questions) + for question, q_answer in questions: + print("- - - - - - - - - - - -\n") + print(f"Вопрос: \n{question}\n") + answer = input("Ваш ответ: ") + if answer.strip().lower() == q_answer.strip().lower(): + print(f"Верно") + score += 1 + else: + print("Не верно") + + print(f"Результат: {score} балла") + old_rating = db.rating.get(user.name, 0) + if old_rating < score: + db.rating[user.name] = score + print(f"Ваш рейтинг обновлен и составляет: {score} балла") + db.commit() + else: + print("Вы набрали меньший балл, и ваш рейтинг оставлен без изменений") + + +def main(): + modes = [ + registration, + login, + print_account_details, + open_account, + user_verification, + addition_from_card, + payment_for_phone, + quiz, + logout, + ] + while True: + print("Выберите режим:") + for i, func in enumerate(modes, 1): + print(f"{i} - {func.__doc__}") + print(" [ Для выхода введите любую другую строку или нажмите Ввод ] ") + i = input("Ваш выбор: ") + if not i.isdigit() or not 0 < int(i) <= len(modes): + print("Выход") + return + mode = modes[int(i) - 1] + print(f"Режим: {mode.__doc__}") + mode() + + +# не пишу тут if __name__ == "__main__": +# чтобы можно было вставить например в ipython или ptpython и т.д. +main()