Files
botPillbox/app/handlers.py
2026-01-06 13:39:22 +07:00

250 lines
8.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# handlers.py
import logging
from datetime import datetime, timedelta
from telegram import Update, ReplyKeyboardRemove
from telegram.ext import ContextTypes, ConversationHandler, CallbackQueryHandler, MessageHandler, filters
from config import *
from app.utils import *
from database import get_db_connection
logger = logging.getLogger(__name__)
# ----------------- BASIC HANDLERS -----------------
async def help_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Обработчик команды /help"""
help_text = """
🤖 *Помощь по боту-напоминалке*
*Основные команды:*
/start - Начать работу с ботом
/help - Показать это сообщение
*Как пользоваться:*
1. Сначала настройте часовой пояс
2. Добавьте лекарства через меню
3. Бот будет присылать напоминания
4. Нажимайте "✅ Выпил(-а)" в напоминании
*Меню:*
Добавить лекарство - добавить новое лекарство
📋 Мои лекарства - список всех лекарств
✏️ Редактировать - изменить параметры лекарства
🗑 Удалить - удалить лекарство
📅 История (7 дней) - история приёмов
🌍 Установить часовой пояс - сменить часовой пояс
❌ Отмена - отменить текущее действие
"""
await update.message.reply_text(help_text, parse_mode='Markdown', reply_markup=main_menu_kb())
return S_MAIN_MENU
async def unknown_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Обработчик неизвестных команд"""
await update.message.reply_text(
"Неизвестная команда. Используйте /help для списка команд.",
reply_markup=main_menu_kb()
)
return S_MAIN_MENU
async def cancel_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Обработчик кнопки Отмена"""
await update.message.reply_text("Отмена.", reply_markup=main_menu_kb())
return S_MAIN_MENU
# ----------------- LIST PILLS -----------------
async def list_pills(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_id = update.effective_user.id
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(
'''SELECT id, name, dose, interval_days, weekdays, course_days, start_date
FROM pills WHERE user_id=?''',
(user_id,)
)
rows = cursor.fetchall()
if not rows:
await update.message.reply_text(
"У вас нет добавленных лекарств.",
reply_markup=main_menu_kb()
)
conn.close()
return S_MAIN_MENU
lines = []
for r in rows:
pid = r["id"]
name = r["name"]
dose = r["dose"]
interval_days = r["interval_days"]
weekdays = r["weekdays"]
course_days = r["course_days"]
start_date = r["start_date"]
cursor.execute(
'SELECT time FROM pill_times WHERE pill_id=?',
(pid,)
)
times = [t["time"] for t in cursor.fetchall()]
freq = ""
if weekdays:
day_names = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"]
selected = [day_names[i] for i in weekdays_csv_to_list(weekdays)]
freq = f"по дням ({', '.join(selected)})"
else:
if interval_days > 1:
freq = f"каждые {interval_days} дн."
else:
freq = "каждый день"
course_info = f"курс {course_days} дн." if course_days > 0 else "бессрочно"
lines.append(
f"ID {pid}: {name}{dose}\n"
f"⏰ Время: {', '.join(times)}\n"
f"📅 {freq} | {course_info} (с {start_date})\n"
)
conn.close()
await update.message.reply_text(
"\n".join(lines),
reply_markup=main_menu_kb()
)
return S_MAIN_MENU
# ----------------- HISTORY -----------------
async def history_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_id = update.effective_user.id
conn = get_db_connection()
cursor = conn.cursor()
try:
# Проверяем, есть ли вообще история за последние 7 дней
seven_days_ago = (datetime.utcnow() - timedelta(days=7)).date().strftime("%Y-%m-%d")
cursor.execute(
'''SELECT COUNT(*) as cnt FROM history
WHERE user_id=? AND date(ts) >= ?''',
(user_id, seven_days_ago)
)
has_history = cursor.fetchone()["cnt"] > 0
if not has_history:
await update.message.reply_text(
"📭 История приёмов за последние 7 дней пуста.\n\n"
"Как только вы отметите приём лекарства (кнопка '✅ Выпил(-а)'), "
"здесь появится история.",
reply_markup=main_menu_kb()
)
conn.close()
return S_MAIN_MENU
# Получаем все лекарства пользователя
cursor.execute('SELECT id, name FROM pills WHERE user_id=?', (user_id,))
pills = cursor.fetchall()
now = datetime.utcnow().date()
lines = []
for pill in pills:
pid = pill["id"]
name = pill["name"]
lines.append(f"💊 {name}:")
for d in range(6, -1, -1):
day = now - timedelta(days=d)
day_str = day.strftime("%Y-%m-%d")
cursor.execute('SELECT COUNT(*) as cnt FROM history WHERE pill_id=? AND user_id=? AND date(ts)=?',
(pid, user_id, day_str))
cnt = cursor.fetchone()["cnt"]
mark = "" if cnt > 0 else ""
lines.append(f"{day.strftime('%d.%m')}: {mark}")
lines.append("")
response = "\n".join(lines)
await update.message.reply_text(response, reply_markup=main_menu_kb())
except Exception as e:
logger.error(f"Error in history_handler: {e}")
await update.message.reply_text(
"❌ Ошибка при получении истории.",
reply_markup=main_menu_kb()
)
finally:
conn.close()
return S_MAIN_MENU
# ----------------- CALLBACK: TAKEN -----------------
async def callback_taken(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
if not query.data or not query.data.startswith("take:"):
await query.edit_message_text("Неизвестная команда.")
return
try:
ptid = int(query.data.split(":", 1)[1])
except ValueError:
await query.edit_message_text("Ошибка в данных.")
return
conn = get_db_connection()
cursor = conn.cursor()
try:
cursor.execute(
'''SELECT pt.pill_id, p.user_id, p.name
FROM pill_times pt
JOIN pills p ON p.id = pt.pill_id
WHERE pt.id=?''',
(ptid,)
)
row = cursor.fetchone()
if not row:
await query.edit_message_text("Запись не найдена.")
conn.close()
return
pid = row["pill_id"]
user_id = row["user_id"]
pill_name = row["name"]
now_utc = datetime.utcnow()
now_min_str = utc_str_min(now_utc)
now_full_str = utc_str_full(now_utc)
cursor.execute(
'UPDATE pill_times SET last_confirmed=? WHERE id=?',
(now_min_str, ptid)
)
cursor.execute(
'''INSERT INTO history (pill_id, user_id, ts, taken)
VALUES (?, ?, ?, 1)''',
(pid, user_id, now_full_str)
)
conn.commit()
await query.edit_message_reply_markup(reply_markup=None)
await query.message.reply_text(
f"✅ Приём '{pill_name}' зарегистрирован!\n"
"Спасибо, что заботишься о своём здоровье 💖",
reply_markup=main_menu_kb()
)
except Exception as e:
logger.error(f"Error in callback_taken: {e}")
await query.edit_message_text("Произошла ошибка.")
finally:
conn.close()