v0.0.5
This commit is contained in:
250
app/handlers.py
Normal file
250
app/handlers.py
Normal file
@@ -0,0 +1,250 @@
|
||||
#!/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 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()
|
||||
Reference in New Issue
Block a user