from telebot.types import Message from daemons.bot import bot from daemons.fetch import fetch_schedule_for_user from helpers import get_next_daily_notify_time from helpers.keyboards import main_keyboard, notify_keyboard, yes_no_keyboard, again_keyboard, groups_keyboard, \ no_daily_notify, student_or_teacher_keyboard, campus_keyboard, daily_notify_type, notify_type, first_lesson_notify from helpers.models import UserSchema, User from helpers.mongo import mongo from helpers.ruz import ruz class BaseAnswer: def process(self, message: Message): user = mongo.users_collection.find_one({"chat_id": message.chat.id}) if user is None: user = User(chat_id=message.chat.id) mongo.users_collection.insert_one(UserSchema().dump(user)) else: user = UserSchema().load(user) attr = getattr(self, "handle_state_" + user.state, None) if attr is None: raise NotImplementedError(f"handled state {user.state} but not implemented!") attr(message, user) def set_state(self, user: User, state: str): user.state = state mongo.users_collection.update_one({"chat_id": user.chat_id}, {"$set": {"state": state}}) class Answer(BaseAnswer): def handle_state_new(self, message: Message, user: User): bot.send_message( message.chat.id, "Привет! Я буду помогать тебе выживать в вышке!\nИз какого ты кампуса?", reply_markup=campus_keyboard() ) self.set_state(user, "wait_for_campus") def handle_state_wait_for_campus(self, message: Message, user: User): if message.text not in ["Москва", "Санкт-Петербург", "Нижний Новгород", "Пермь"]: bot.send_message( user.chat_id, "Ты прислал мне что-то непонятное, используй кнопки. Из какого ты кампуса?", reply_markup=campus_keyboard() ) return bot.send_message( user.chat_id, "Принято! Ты преподаватель или студент?", reply_markup=student_or_teacher_keyboard() ) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"campus": message.text, "state": "wait_for_student_or_teacher"}} ) def handle_state_wait_for_student_or_teacher(self, message: Message, user: User): if message.text == "Студент 👨‍🎓": bot.send_message(user.chat_id, "Принято! Теперь отправь мне свое ФИО.", reply_markup=again_keyboard()) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"is_teacher": False, "state": "wait_for_name"}} ) self.set_state(user, "wait_for_name") elif message.text == "Преподаватель 👨‍🏫": bot.send_message(user.chat_id, "Принято! Теперь отправь мне свое ФИО.", reply_markup=again_keyboard()) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"is_teacher": True, "state": "wait_for_name"}} ) self.set_state(user, "wait_for_name") elif message.text == "Начать заново 🔄": bot.send_message( message.chat.id, "Привет! Я буду помогать тебе выживать в вышке!\nИз какого ты кампуса?", reply_markup=campus_keyboard() ) self.set_state(user, "wait_for_campus") return else: bot.send_message(user.chat_id, "Ты отправил мне что-то неправильное, используй кнопки. Ты преподаватель или студент?", reply_markup=student_or_teacher_keyboard()) def handle_state_wait_for_name(self, message: Message, user: User): if message.text == "Начать заново 🔄": bot.send_message( message.chat.id, "Привет! Я буду помогать тебе выживать в вышке!\nИз какого ты кампуса?", reply_markup=campus_keyboard() ) self.set_state(user, "wait_for_campus") return user.name = message.text data = ruz.find_person(user) if data is None: bot.send_message( user.chat_id, "В РУЗе какая-то поломка, попробуй еще раз позже." ) return if len(data) == 0: bot.send_message(user.chat_id, "К сожалению, в РУЗе не нашлось такого человека, попробуй еще раз.") return mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"name": user.name}}) if user.is_teacher: bot.send_message( user.chat_id, "Отлично! Теперь выбери из списка свой департамент.", reply_markup=groups_keyboard(data) ) else: bot.send_message( user.chat_id, "Отлично! Теперь выбери из списка свою группу.", reply_markup=groups_keyboard(data) ) self.set_state(user, "wait_for_group") def handle_state_wait_for_group(self, message: Message, user: User): if message.text == "Начать заново 🔄": bot.send_message( message.chat.id, "Привет! Я буду помогать тебе выживать в вышке!\nИз какого ты кампуса?", reply_markup=campus_keyboard() ) self.set_state(user, "wait_for_campus") return group = message.text data = ruz.find_person(user) if data is None: bot.send_message( user.chat_id, "В РУЗе какая-то поломка, попробуй еще раз позже." ) return for element in data: if element['description'] == group: user.hse_id = int(element['id']) user.group = group user.name = element['label'] break if user.group is None: bot.send_message(user.chat_id, "Ты ввел что-то неправильно, попробуй еще раз сначала. Из какого ты кампуса?", reply_markup=campus_keyboard()) self.set_state(user, "wait_for_campus") return mongo.users_collection.update_one({"chat_id": user.chat_id}, {"$set": { "hse_id": user.hse_id, "group": group, "name": user.name }}) bot.send_message( user.chat_id, "Я нашел тебя в базе РУЗ. Я буду подсказывать тебе расписание, а также уведомлять о предстоящих парах.", ) success = fetch_schedule_for_user(user) if success: lessons = mongo.get_today_lessons(user) if len(lessons) == 0: bot.send_message( user.chat_id, "Сегодня у тебя нет пар, отдыхай", reply_markup=main_keyboard() ) else: bot.send_message( user.chat_id, "Твои пары сегодня:\n" + ruz.schedule_builder(lessons), reply_markup=main_keyboard(), parse_mode='Markdown', ) self.set_state(user, "ready") def handle_state_ready(self, message: Message, user: User): if message.text == "Пары сегодня": lessons = mongo.get_today_lessons(user) if len(lessons) == 0: text = "Сегодня у тебя нет пар, отдыхай." else: text = ruz.schedule_builder(lessons) elif message.text == "Пары завтра": lessons = mongo.get_tomorrow_lessons(user) if len(lessons) == 0: text = "Завтра у тебя нет пар, отдыхай." else: text = ruz.schedule_builder(lessons) elif message.text == "Расписание на неделю": lessons = mongo.get_week_lessons(user) if len(lessons) == 0: text = "На этой неделе у тебя нет пар, отдыхай." else: text = ruz.schedule_builder(lessons) elif message.text == "Напоминания о парах": bot.send_message( user.chat_id, "Я умею напоминать о каждой паре и о первой паре. Что хочешь настроить?", reply_markup=notify_type() ) self.set_state(user, "notify_type") return elif message.text == "Ежедневные уведомления": bot.send_message( user.chat_id, "Я могу присылать тебе расписание на текущий день или на следующий. Как ты хочешь чтобы я тебя уведомлял?", reply_markup=daily_notify_type() ) self.set_state(user, "wait_for_daily_notify_type") return elif message.text == "Сброс настроек": bot.send_message(user.chat_id, "Ты уверен что хочешь сбросить все настройки и больше не получать уведомления?", reply_markup=yes_no_keyboard()) self.set_state(user, "reset") return elif message.text == "Подключение Алисы": if user.yandex_id is None: text = "Для того, чтобы подключить Яндекс.Алису, вызови навык \"Расписание вышки\" и назови этот код: " + str(user.hse_id) else: text = "Янедкс.Алиса уже подключена. Чтобы узнать ближайшую пару, вызови навык \"Расписание вышки\"" else: text = "Я не понимаю такой команды, используй кнопки." bot.send_message( user.chat_id, text, reply_markup=main_keyboard(), parse_mode='Markdown' ) def handle_state_notify_type(self, message: Message, user: User): text = message.text if text == "О каждой паре": bot.send_message( user.chat_id, "Выбери за сколько минут мне нужно напомнить тебе о предстоящей паре", reply_markup=notify_keyboard() ) self.set_state(user, "wait_for_notify") elif text == "О первой паре": bot.send_message( user.chat_id, "Выбери за сколько минут мне нужно напоминать тебе о первой паре", reply_markup=first_lesson_notify() ) self.set_state(user, "wait_for_first_notify") elif text == "Назад": self.set_state(user, "ready") bot.send_message( user.chat_id, text, reply_markup=main_keyboard() ) else: bot.send_message(user.chat_id, "Используй кнопки!", reply_markup=notify_type()) def handle_state_wait_for_first_notify(self, message: Message, user: User): text = message.text if text == "30 минут": time_notify = 30 elif text == "1 час": time_notify = 60 elif text == "4 часа": time_notify = 4 * 60 elif text == "12 часов": time_notify = 12 * 60 elif text == "Не уведомлять": time_notify = None else: bot.send_message(user.chat_id, "Используй кнопки!", reply_markup=first_lesson_notify()) return mongo.users_collection.update_one({"chat_id": user.chat_id}, {"$set": {"first_lesson_notify": time_notify}}) self.set_state(user, "ready") bot.send_message(user.chat_id, "Запомнил!", reply_markup=main_keyboard()) def handle_state_wait_for_daily_notify_type(self, message: Message, user: User): text = message.text if text == "Текущий день": bot.send_message( user.chat_id, "Каждый день (кроме воскресенья) я буду присылать тебе расписание на текущий день. Пришли мне в формате чч:мм время, в которое ты хочешь получать расписание. Например, 09:30", reply_markup=no_daily_notify() ) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"daily_notify_today": True, "state": "wait_for_daily_notify"}} ) elif text == "Следующий день": bot.send_message( user.chat_id, "Каждый день (кроме субботы) я буду присылать тебе расписание на следующий день. Пришли мне в формате чч:мм время, в которое ты хочешь получать расписание. Например, 20:30", reply_markup=no_daily_notify() ) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"daily_notify_today": False, "state": "wait_for_daily_notify"}} ) elif text == "Не уведомлять": bot.send_message( user.chat_id, "Принято! Я не буду уведомлять тебя.", reply_markup=main_keyboard() ) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"next_daily_notify_time": None, "daily_notify_time": None, "state": "ready"}} ) elif text == "Назад": bot.send_message( user.chat_id, "Возвращаюсь!", reply_markup=main_keyboard() ) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"next_daily_notify_time": None, "daily_notify_time": None, "state": "ready"}} ) else: bot.send_message( user.chat_id, "Ты прислал мне что-то неправильное, используй кнопки. Как ты хочешь чтобы я тебя уведомлял?", reply_markup=daily_notify_type() ) def handle_state_wait_for_notify(self, message: Message, user: User): text = message.text if text == "Не уведомлять": user.notify_minutes = None elif text == "5 минут": user.notify_minutes = 5 elif text == "10 минут": user.notify_minutes = 10 elif text == "15 минут": user.notify_minutes = 15 elif text == "20 минут": user.notify_minutes = 20 else: bot.send_message( user.chat_id, "Я не понимаю такой команды, используй кнопки.", reply_markup=notify_keyboard() ) return mongo.users_collection.update_one({"chat_id": user.chat_id}, {"$set": {"notify_minutes": user.notify_minutes}}) if user.notify_minutes is not None: text = f"Принято! Буду уведомлять тебя за {text}." else: text = f"Принято! Я не буду уведомлять тебя." bot.send_message(user.chat_id, text, reply_markup=main_keyboard()) self.set_state(user, "ready") def _validate_time(self, line: str) -> bool: if len(line) != 5: return False if line.count(":") != 1: return False hours, minutes = line.split(":") try: hours = int(hours) minutes = int(minutes) except ValueError: return False if hours < 0 or hours > 23 or minutes < 0 or minutes > 59: return False return True def handle_state_wait_for_daily_notify(self, message: Message, user: User): text = message.text if text == "Не уведомлять": bot.send_message( user.chat_id, "Принято! Я не буду присылать тебе ежедневные уведомления.", reply_markup=main_keyboard() ) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": {"daily_notify_time": None, "next_daily_notify_time": None, "state": "ready"}} ) return if not self._validate_time(text): bot.send_message( user.chat_id, "Ты прислал мне что-то неправильное. Пришли мне в формате чч:мм время, в которое ты хочешь получать расписание. Например, 09:30", reply_markup=no_daily_notify() ) return user.daily_notify_time = text next_time = get_next_daily_notify_time(user) bot.send_message( user.chat_id, f"Принято! Буду уведомлять тебя каждый день в {text}.", reply_markup=main_keyboard() ) mongo.users_collection.update_one( {"chat_id": user.chat_id}, {"$set": { "daily_notify_time": text, "next_daily_notify_time": next_time, "state": "ready" }} ) def handle_state_reset(self, message: Message, user: User): if message.text == "Да": mongo.users_collection.delete_one({"chat_id": user.chat_id}) bot.send_message(user.chat_id, "Настройки сброшены, ждем твоего возвращения", reply_markup=again_keyboard()) elif message.text == "Нет": bot.send_message(user.chat_id, "Возращаюсь к прежнему режиму", reply_markup=main_keyboard()) self.set_state(user, "ready") else: bot.send_message(user.chat_id, "Я не понимаю, используй кнопки", reply_markup=yes_no_keyboard()) answer = Answer()