daily notify
This commit is contained in:
parent
54c47001b7
commit
61436be630
@ -1,14 +1,14 @@
|
||||
import datetime
|
||||
import zoneinfo
|
||||
from time import sleep
|
||||
|
||||
from helpers import now
|
||||
from helpers.mongo import mongo
|
||||
from helpers.ruz import ruz
|
||||
from settings import MOSCOW_TIMEZONE
|
||||
|
||||
|
||||
def fetch_schedule_for_user(user_hse_id: int):
|
||||
zone = zoneinfo.ZoneInfo("Europe/Moscow")
|
||||
today = datetime.datetime.now(zone)
|
||||
today = now()
|
||||
next_day = today + datetime.timedelta(days=7)
|
||||
schedule = ruz.get_schedule(user_hse_id, today, next_day)
|
||||
if schedule is None:
|
||||
@ -27,7 +27,8 @@ def fetch_schedule_for_user(user_hse_id: int):
|
||||
month=int(month),
|
||||
day=int(day),
|
||||
hour=int(begin_hour),
|
||||
minute=int(begin_minute)
|
||||
minute=int(begin_minute),
|
||||
tzinfo=MOSCOW_TIMEZONE
|
||||
)
|
||||
})
|
||||
if lesson is None:
|
||||
@ -40,14 +41,16 @@ def fetch_schedule_for_user(user_hse_id: int):
|
||||
month=int(month),
|
||||
day=int(day),
|
||||
hour=int(begin_hour),
|
||||
minute=int(begin_minute)
|
||||
minute=int(begin_minute),
|
||||
tzinfo=MOSCOW_TIMEZONE
|
||||
),
|
||||
"end": datetime.datetime(
|
||||
year=int(year),
|
||||
month=int(month),
|
||||
day=int(day),
|
||||
hour=int(end_hour),
|
||||
minute=int(end_minute)
|
||||
minute=int(end_minute),
|
||||
tzinfo=MOSCOW_TIMEZONE
|
||||
),
|
||||
"building": element['building'],
|
||||
"lecturer": element['lecturer'],
|
||||
@ -66,9 +69,7 @@ def process():
|
||||
|
||||
|
||||
def delete_old():
|
||||
zone = zoneinfo.ZoneInfo("Europe/Moscow")
|
||||
today = datetime.datetime.now(zone)
|
||||
mongo.lessons_collection.delete_many({"end": {"$lte": today - datetime.timedelta(days=1)}})
|
||||
mongo.lessons_collection.delete_many({"end": {"$lte": now() - datetime.timedelta(days=1)}})
|
||||
|
||||
|
||||
def fetch():
|
||||
|
@ -2,19 +2,42 @@ import datetime
|
||||
import zoneinfo
|
||||
from time import sleep
|
||||
|
||||
import croniter
|
||||
import pytz
|
||||
from telebot.apihelper import ApiTelegramException
|
||||
|
||||
from daemons.bot import bot
|
||||
from helpers import now
|
||||
from helpers.keyboards import main_keyboard
|
||||
from helpers.models import UserSchema
|
||||
from helpers.mongo import mongo
|
||||
from helpers.ruz import ruz
|
||||
|
||||
|
||||
def process():
|
||||
for user in mongo.users_collection.find({"hse_id": {"$ne": None}, "next_notify_time": {"$lte": now()}}):
|
||||
try:
|
||||
lessons = mongo.get_today_lessons(UserSchema().load(user))
|
||||
if len(lessons) == 0:
|
||||
ans = "Сегодня у тебя нет пар."
|
||||
else:
|
||||
ans = ruz.schedule_builder(lessons)
|
||||
bot.send_message(
|
||||
user['chat_id'],
|
||||
"Напоминаю о занятиях сегодня!\n" + ans,
|
||||
reply_markup=main_keyboard()
|
||||
)
|
||||
except:
|
||||
pass
|
||||
hours, minutes = user['notify_daily'].split(':')
|
||||
cron = croniter.croniter(f"{minutes} {hours} * * *", now())
|
||||
next_date = cron.get_next(datetime.datetime)
|
||||
next_date = next_date.replace(tzinfo=pytz.timezone('Europe/Moscow'))
|
||||
mongo.users_collection.update_one({"chat_id": user['chat_id']}, {"$set": {"next_notify_time": next_date}})
|
||||
for user in mongo.users_collection.find({"notify_minutes": {"$ne": None}, "hse_id": {"$ne": None}}):
|
||||
zone = zoneinfo.ZoneInfo("Europe/Moscow")
|
||||
now = datetime.datetime.now(zone)
|
||||
for lesson in mongo.lessons_collection.find({
|
||||
"hse_user_id": user["hse_id"],
|
||||
"begin": {"$lte": now + datetime.timedelta(minutes=5)},
|
||||
"begin": {"$lte": now() + datetime.timedelta(minutes=5)},
|
||||
"notified": False
|
||||
}):
|
||||
ans = ""
|
||||
|
@ -0,0 +1,8 @@
|
||||
import datetime
|
||||
import zoneinfo
|
||||
|
||||
|
||||
def now():
|
||||
zone = zoneinfo.ZoneInfo("Europe/Moscow")
|
||||
today = datetime.datetime.now(zone)
|
||||
return today
|
@ -1,8 +1,14 @@
|
||||
import telebot
|
||||
import datetime
|
||||
|
||||
import croniter
|
||||
import pytz
|
||||
from telebot.types import Message
|
||||
|
||||
from daemons.bot import bot
|
||||
from daemons.fetch import fetch_schedule_for_user
|
||||
from helpers import now
|
||||
from helpers.keyboards import main_keyboard, notify_keyboard, yes_no_keyboard, again_keyboard, groups_keyboard, \
|
||||
no_daily_notify
|
||||
from helpers.models import UserSchema, User
|
||||
from helpers.mongo import mongo
|
||||
from helpers.ruz import ruz
|
||||
@ -12,9 +18,21 @@ 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)
|
||||
cron = croniter.croniter("0 9 * * *", now())
|
||||
next_date = cron.get_next(datetime.datetime)
|
||||
next_date = next_date.replace(tzinfo=pytz.timezone('Europe/Moscow'))
|
||||
user = User(chat_id=message.chat.id, next_notify_time=next_date)
|
||||
mongo.users_collection.insert_one(UserSchema().dump(user))
|
||||
else:
|
||||
if "next_notify_time" not in user:
|
||||
cron = croniter.croniter("0 9 * * *", now())
|
||||
next_date = cron.get_next(datetime.datetime)
|
||||
next_date = next_date.replace(tzinfo=pytz.timezone('Europe/Moscow'))
|
||||
user["next_notify_time"] = next_date
|
||||
mongo.users_collection.update_one(
|
||||
{"chat_id": message.chat.id},
|
||||
{"$set": {"next_notify_time": next_date}}
|
||||
)
|
||||
user = UserSchema().load(user)
|
||||
attr = getattr(self, "handle_state_" + user.state, None)
|
||||
if attr is None:
|
||||
@ -36,7 +54,6 @@ class Answer(BaseAnswer):
|
||||
self.set_state(user, "wait_for_name")
|
||||
|
||||
def handle_state_wait_for_name(self, message: Message, user: User):
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
data = ruz.find_person(message.text)
|
||||
if data is None:
|
||||
bot.send_message(
|
||||
@ -47,8 +64,6 @@ class Answer(BaseAnswer):
|
||||
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},
|
||||
@ -56,7 +71,7 @@ class Answer(BaseAnswer):
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"Отлично! Теперь выбери из списка свою группу.",
|
||||
reply_markup=kb
|
||||
reply_markup=groups_keyboard(data)
|
||||
)
|
||||
self.set_state(user, "wait_for_group")
|
||||
|
||||
@ -90,55 +105,46 @@ class Answer(BaseAnswer):
|
||||
)
|
||||
success = fetch_schedule_for_user(user.hse_id)
|
||||
if success:
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Пары сегодня")
|
||||
kb.row("Уведомления")
|
||||
kb.row("Сброс настроек")
|
||||
lessons = mongo.get_today_lessons(user)
|
||||
if len(lessons) == 0:
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"Сегодня у тебя нет пар.",
|
||||
reply_markup=kb
|
||||
reply_markup=main_keyboard()
|
||||
)
|
||||
else:
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
ruz.schedule_builder(lessons),
|
||||
reply_markup=kb
|
||||
reply_markup=main_keyboard()
|
||||
)
|
||||
self.set_state(user, "ready")
|
||||
|
||||
def handle_state_ready(self, message: Message, user: User):
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Пары сегодня")
|
||||
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, False)
|
||||
kb.row("Не уведомлять")
|
||||
kb.row("5 минут")
|
||||
kb.row("10 минут")
|
||||
kb.row("15 минут")
|
||||
kb.row("20 минут")
|
||||
elif message.text == "Уведомления о парах":
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"Выбери когда мне нужно тебе написать о предстоящей паре",
|
||||
reply_markup=kb
|
||||
reply_markup=notify_keyboard()
|
||||
)
|
||||
self.set_state(user, "wait_for_notify")
|
||||
return
|
||||
elif message.text == "Ежедневные уведомления":
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"Пришли время в формате чч:мм во сколько ты хочешь получать уведомления о парах в этот день. Например, 09:30",
|
||||
reply_markup=no_daily_notify()
|
||||
)
|
||||
self.set_state(user, "wait_for_daily_notify")
|
||||
return
|
||||
elif message.text == "Сброс настроек":
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Да")
|
||||
kb.row("Нет")
|
||||
bot.send_message(user.chat_id, "Ты уверен что хочешь сбросить все настройки и больше не получать уведомления?", reply_markup=kb)
|
||||
bot.send_message(user.chat_id, "Ты уверен что хочешь сбросить все настройки и больше не получать уведомления?", reply_markup=yes_no_keyboard())
|
||||
self.set_state(user, "reset")
|
||||
return
|
||||
else:
|
||||
@ -146,7 +152,7 @@ class Answer(BaseAnswer):
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
text,
|
||||
reply_markup=kb
|
||||
reply_markup=main_keyboard()
|
||||
)
|
||||
|
||||
def handle_state_wait_for_notify(self, message: Message, user: User):
|
||||
@ -162,46 +168,71 @@ class Answer(BaseAnswer):
|
||||
elif text == "20 минут":
|
||||
user.notify_minutes = 20
|
||||
else:
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Не уведомлять")
|
||||
kb.row("5 минут")
|
||||
kb.row("10 минут")
|
||||
kb.row("15 минут")
|
||||
kb.row("20 минут")
|
||||
bot.send_message(user.chat_id, "Я не понимаю такой команды, используй кнопки.", reply_markup=kb)
|
||||
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"Принято! Я не уведомлять тебя."
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Пары сегодня")
|
||||
kb.row("Уведомления")
|
||||
kb.row("Сброс настроек")
|
||||
bot.send_message(user.chat_id, text, reply_markup=kb)
|
||||
bot.send_message(user.chat_id, text, reply_markup=main_keyboard())
|
||||
self.set_state(user, "ready")
|
||||
|
||||
def handle_state_reset(self, message: Message, user: User):
|
||||
if message.text == "Да":
|
||||
mongo.users_collection.delete_one({"hse_id": user.hse_id})
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Начать заново")
|
||||
bot.send_message(user.chat_id, "Настройки сброшены, ждем твоего возвращения", reply_markup=kb)
|
||||
bot.send_message(user.chat_id, "Настройки сброшены, ждем твоего возвращения", reply_markup=again_keyboard())
|
||||
elif message.text == "Нет":
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Пары сегодня")
|
||||
kb.row("Уведомления")
|
||||
kb.row("Сброс настроек")
|
||||
bot.send_message(user.chat_id, "Возращаюсь к прежнему режиму", reply_markup=kb)
|
||||
bot.send_message(user.chat_id, "Возращаюсь к прежнему режиму", reply_markup=main_keyboard())
|
||||
self.set_state(user, "ready")
|
||||
else:
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Да")
|
||||
kb.row("Нет")
|
||||
bot.send_message(user.chat_id,
|
||||
"Я не понимаю, используй кнопки",
|
||||
reply_markup=kb)
|
||||
reply_markup=yes_no_keyboard())
|
||||
|
||||
def _check_time_correct(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:
|
||||
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 not self._check_time_correct(text):
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
"Ты прислал что-то неправильное. Пришли время в формате чч:мм. Например, 09:30",
|
||||
reply_markup=no_daily_notify()
|
||||
)
|
||||
return
|
||||
user.notify_daily = message.text
|
||||
hours, minutes = user.notify_daily.split(':')
|
||||
cron = croniter.croniter(f"{minutes} {hours} * * *", now())
|
||||
next_date = cron.get_next(datetime.datetime)
|
||||
next_date = next_date.replace(tzinfo=pytz.timezone('Europe/Moscow'))
|
||||
mongo.users_collection.update_one({"chat_id": user.chat_id}, {"$set": {
|
||||
"notify_daily": message.text,
|
||||
"next_notify_time": next_date
|
||||
}})
|
||||
bot.send_message(
|
||||
user.chat_id,
|
||||
f"Принято! Буду каждый день уведомлять тебя в {message.text}",
|
||||
reply_markup=main_keyboard()
|
||||
)
|
||||
self.set_state(user, "ready")
|
||||
|
||||
|
||||
answer = Answer()
|
||||
|
46
helpers/keyboards.py
Normal file
46
helpers/keyboards.py
Normal file
@ -0,0 +1,46 @@
|
||||
import telebot
|
||||
|
||||
|
||||
def main_keyboard():
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Пары сегодня")
|
||||
kb.row("Уведомления о парах")
|
||||
kb.row("Ежедневные уведомления")
|
||||
kb.row("Сброс настроек")
|
||||
return kb
|
||||
|
||||
|
||||
def notify_keyboard():
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Не уведомлять")
|
||||
kb.row("5 минут")
|
||||
kb.row("10 минут")
|
||||
kb.row("15 минут")
|
||||
kb.row("20 минут")
|
||||
return kb
|
||||
|
||||
|
||||
def yes_no_keyboard():
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Да")
|
||||
kb.row("Нет")
|
||||
return kb
|
||||
|
||||
|
||||
def again_keyboard():
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Начать заново")
|
||||
return kb
|
||||
|
||||
|
||||
def groups_keyboard(data):
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
for entity in data:
|
||||
kb.row(entity['description'])
|
||||
return kb
|
||||
|
||||
|
||||
def no_daily_notify():
|
||||
kb = telebot.types.ReplyKeyboardMarkup(True, False)
|
||||
kb.row("Не уведомлять")
|
||||
return kb
|
@ -1,3 +1,4 @@
|
||||
import datetime
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
@ -8,6 +9,8 @@ from marshmallow import EXCLUDE
|
||||
@dataclass
|
||||
class User:
|
||||
chat_id: int
|
||||
next_notify_time: datetime.datetime
|
||||
notify_daily: Optional[str] = "09:00"
|
||||
name: Optional[str] = None
|
||||
group: Optional[str] = None
|
||||
hse_id: Optional[int] = None
|
||||
|
@ -5,6 +5,7 @@ from functools import cached_property
|
||||
import pymongo
|
||||
|
||||
import settings
|
||||
from helpers import now
|
||||
from helpers.models import UserSchema, User
|
||||
|
||||
|
||||
@ -50,8 +51,7 @@ class Mongo:
|
||||
return self["lessons"]
|
||||
|
||||
def get_today_lessons(self, user: User):
|
||||
zone = zoneinfo.ZoneInfo("Europe/Moscow")
|
||||
today = datetime.datetime.now(zone)
|
||||
today = now()
|
||||
tomorrow = today + datetime.timedelta(days=1)
|
||||
tomorrow = datetime.datetime(year=tomorrow.year, month=tomorrow.month, day=tomorrow.day)
|
||||
lessons = []
|
||||
|
@ -1,5 +1,5 @@
|
||||
import os
|
||||
|
||||
import zoneinfo
|
||||
|
||||
MONGO_USER = os.getenv("MONGO_USER", "mongo")
|
||||
MONGO_PASSWORD = os.getenv("MONGO_PASSWORD", "password")
|
||||
@ -7,3 +7,4 @@ MONGO_HOST = os.getenv("MONGO_HOST", "localhost")
|
||||
DEBUG = os.getenv("DEBUG", "true") == "true"
|
||||
|
||||
RUZ_API = "https://ruz.hse.ru/api/"
|
||||
MOSCOW_TIMEZONE = zoneinfo.ZoneInfo("Europe/Moscow")
|
||||
|
Loading…
Reference in New Issue
Block a user