initial
This commit is contained in:
0
helpers/__init__.py
Normal file
0
helpers/__init__.py
Normal file
172
helpers/answer.py
Normal file
172
helpers/answer.py
Normal file
@@ -0,0 +1,172 @@
|
||||
import telebot
|
||||
from telebot.types import Message
|
||||
|
||||
from daemons.bot import bot
|
||||
from daemons.fetch import fetch_schedule_for_user
|
||||
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Для начала пришли мне свое ФИО.",
|
||||
)
|
||||
self.set_state(user, "wait_for_name")
|
||||
|
||||
def handle_state_wait_for_name(self, message: Message, user: User):
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, True)
|
||||
data = ruz.find_person(message.text)
|
||||
if data is None:
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"В РУЗе какая-то поломка, попробуй еще раз позже."
|
||||
)
|
||||
return
|
||||
if len(data) == 0:
|
||||
bot.send_message(user.chat_id, "К сожалению, в РУЗе не нашлось такого студента, попробуй еще раз.")
|
||||
return
|
||||
for entity in data:
|
||||
kb.row(entity['description'])
|
||||
user.name = message.text
|
||||
mongo.users_collection.update_one(
|
||||
{"chat_id": user.chat_id},
|
||||
{"$set": {"name": user.name}})
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"Отлично! Теперь выбери из списка свою группу.",
|
||||
reply_markup=kb
|
||||
)
|
||||
self.set_state(user, "wait_for_group")
|
||||
|
||||
def handle_state_wait_for_group(self, message: Message, user: User):
|
||||
group = message.text
|
||||
data = ruz.find_person(user.name)
|
||||
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
|
||||
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.hse_id)
|
||||
if success:
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, True)
|
||||
kb.row("Пары сегодня")
|
||||
kb.row("Уведомления")
|
||||
lessons = mongo.get_today_lessons(user)
|
||||
if len(lessons) == 0:
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"Сегодня у тебя нет пар.",
|
||||
reply_markup=kb
|
||||
)
|
||||
else:
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
ruz.schedule_builder(lessons),
|
||||
reply_markup=kb
|
||||
)
|
||||
self.set_state(user, "ready")
|
||||
|
||||
def handle_state_ready(self, message: Message, user: User):
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, True)
|
||||
kb.row("Пары сегодня")
|
||||
kb.row("Уведомления")
|
||||
if message.text == "Пары сегодня":
|
||||
lessons = mongo.get_today_lessons(user)
|
||||
if len(lessons) == 0:
|
||||
text = "Сегодня у тебя нет пар."
|
||||
else:
|
||||
text = ruz.schedule_builder(lessons)
|
||||
elif message.text == "Уведомления":
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, True)
|
||||
kb.row("Не уведомлять")
|
||||
kb.row("5 минут")
|
||||
kb.row("10 минут")
|
||||
kb.row("15 минут")
|
||||
kb.row("20 минут")
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"Выбери когда мне нужно тебе написать о предстоящей паре",
|
||||
reply_markup=kb
|
||||
)
|
||||
self.set_state(user, "wait_for_notify")
|
||||
return
|
||||
else:
|
||||
text = "Я не понимаю такой команды, используй кнопки."
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
text,
|
||||
reply_markup=kb
|
||||
)
|
||||
|
||||
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:
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, True)
|
||||
kb.row("Не уведомлять")
|
||||
kb.row("5 минут")
|
||||
kb.row("10 минут")
|
||||
kb.row("15 минут")
|
||||
kb.row("20 минут")
|
||||
bot.send_message(user.chat_id, "Я не понимаю такой команды, используй кнопки.", reply_markup=kb)
|
||||
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"Принято! Я не уведомлять тебя."
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, True)
|
||||
kb.row("Пары сегодня")
|
||||
kb.row("Уведомления")
|
||||
bot.send_message(user.chat_id, text, reply_markup=kb)
|
||||
self.set_state(user, "ready")
|
||||
|
||||
|
||||
answer = Answer()
|
||||
27
helpers/models.py
Normal file
27
helpers/models.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
import marshmallow_dataclass
|
||||
from marshmallow import EXCLUDE
|
||||
|
||||
|
||||
@dataclass
|
||||
class User:
|
||||
chat_id: int
|
||||
name: Optional[str] = None
|
||||
group: Optional[str] = None
|
||||
hse_id: Optional[int] = None
|
||||
state: str = "new"
|
||||
notify_minutes: Optional[int] = 10
|
||||
|
||||
class Meta:
|
||||
unknown = EXCLUDE
|
||||
|
||||
|
||||
@dataclass
|
||||
class Lesson:
|
||||
hse_id: int
|
||||
|
||||
|
||||
|
||||
UserSchema = marshmallow_dataclass.class_schema(User)
|
||||
66
helpers/mongo.py
Normal file
66
helpers/mongo.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import datetime
|
||||
import zoneinfo
|
||||
from functools import cached_property
|
||||
|
||||
import pymongo
|
||||
|
||||
import settings
|
||||
from helpers.models import UserSchema, User
|
||||
|
||||
|
||||
class Mongo:
|
||||
def __init__(self):
|
||||
url = f"mongodb://{settings.MONGO_USER}:{settings.MONGO_PASSWORD}@{settings.MONGO_HOST}:27017/"
|
||||
self.client = pymongo.MongoClient(url)
|
||||
self.database = self.client.get_database("ruz-bot")
|
||||
self.users_collection.create_index([
|
||||
("chat_id", 1)
|
||||
])
|
||||
self.users_collection.create_index([
|
||||
("notify_minutes", 1)
|
||||
])
|
||||
self.lessons_collection.create_index([
|
||||
("discipline", 1),
|
||||
("auditorium", 1),
|
||||
("begin", 1),
|
||||
("hse_user_id", 1)
|
||||
])
|
||||
self.lessons_collection.create_index([
|
||||
("hse_user_id", 1),
|
||||
("begin", 1)
|
||||
])
|
||||
self.lessons_collection.create_index([
|
||||
("hse_user_id", 1),
|
||||
("begin", 1),
|
||||
("notified", 1)
|
||||
])
|
||||
|
||||
def get_user(self, user_id: int) -> User:
|
||||
return UserSchema().loads(self.users_collection.find_one({"id": user_id}))
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.database.get_collection(item)
|
||||
|
||||
@cached_property
|
||||
def users_collection(self):
|
||||
return self["users"]
|
||||
|
||||
@cached_property
|
||||
def lessons_collection(self):
|
||||
return self["lessons"]
|
||||
|
||||
def get_today_lessons(self, user: User):
|
||||
zone = zoneinfo.ZoneInfo("Europe/Moscow")
|
||||
today = datetime.datetime.now(zone)
|
||||
tomorrow = today + datetime.timedelta(days=1)
|
||||
tomorrow = datetime.datetime(year=tomorrow.year, month=tomorrow.month, day=tomorrow.day)
|
||||
lessons = []
|
||||
for lesson in self.lessons_collection.find({
|
||||
"hse_user_id": user.hse_id,
|
||||
"begin": {"$gte": today, "$lte": tomorrow}}
|
||||
):
|
||||
lessons.append(lesson)
|
||||
return lessons
|
||||
|
||||
|
||||
mongo = Mongo()
|
||||
62
helpers/ruz.py
Normal file
62
helpers/ruz.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import datetime
|
||||
|
||||
from requests import get
|
||||
|
||||
import settings
|
||||
|
||||
|
||||
fields = [
|
||||
'discipline',
|
||||
'building',
|
||||
'auditorium',
|
||||
'date',
|
||||
'beginLesson',
|
||||
'endLesson',
|
||||
'lecturer'
|
||||
]
|
||||
|
||||
|
||||
class RUZ:
|
||||
|
||||
def find_person(self, name: str) -> dict | None:
|
||||
search_str = settings.RUZ_API + f"search?term={name}&type=student"
|
||||
try:
|
||||
data = get(search_str)
|
||||
except:
|
||||
return None
|
||||
if data.status_code == 200:
|
||||
return data.json()
|
||||
return None
|
||||
|
||||
def get_schedule(self, hse_id: int, begin_date: datetime.datetime, end_date: datetime.datetime):
|
||||
start_date_str = begin_date.strftime("%Y.%m.%d")
|
||||
end_date_str = end_date.strftime("%Y.%m.%d")
|
||||
search_str = settings.RUZ_API + f"schedule/student/{hse_id}?start={start_date_str}&finish={end_date_str}&lng=1"
|
||||
try:
|
||||
data = get(search_str)
|
||||
except:
|
||||
return None
|
||||
if data.status_code != 200:
|
||||
return None
|
||||
data = data.json()
|
||||
formatted_data = [
|
||||
{
|
||||
field: element[field]
|
||||
for field in fields
|
||||
}
|
||||
for element in data
|
||||
]
|
||||
return formatted_data
|
||||
|
||||
def schedule_builder(self, lessons: list[dict]) -> str:
|
||||
ans = ""
|
||||
for lesson in lessons:
|
||||
ans += "Аудитория: " + lesson["building"] + ", " + lesson["auditorium"] + "\n"
|
||||
ans += "Начало: " + lesson["begin"].strftime("%H:%M") + "\n"
|
||||
ans += "Конец: " + lesson["end"].strftime("%H:%M") + "\n"
|
||||
ans += "Преподаватель: " + lesson["lecturer"] + "\n"
|
||||
ans += "_______________\n"
|
||||
return ans
|
||||
|
||||
|
||||
ruz = RUZ()
|
||||
Reference in New Issue
Block a user