Вот мой код:
import pytz
import sqlite3
from datetime import datetime, timedelta
from telegram import Update, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, MessageHandler, filters, CallbackQueryHandler, CallbackContext
import configparser
import os
import logging

# Настройка логирования
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
)

# Чтение конфигурационного файла
config = configparser.ConfigParser()
config.read('config.ini')

# Получение токена из конфигурационного файла
TOKEN = config.get('Telegram', 'Token')

# ID главного администратора
MAIN_ADMIN_ID = 1108429314

def create_config_file():
    config['Telegram'] = {'Token': 'your_bot_token_here'}
    with open('config.ini', 'w') as configfile:
        config.write(configfile)

def init_db():
    conn = sqlite3.connect('university.db')
    c = conn.cursor()

    # Создание таблиц и столбцов
    c.execute('''CREATE TABLE IF NOT EXISTS schedule
                 (course INTEGER, direction TEXT, week_type TEXT, day TEXT, slot INTEGER, time TEXT, details TEXT)''')

    c.execute('''CREATE TABLE IF NOT EXISTS users
                 (id INTEGER PRIMARY KEY, username TEXT, course INTEGER, direction TEXT, 
                 subscribed INTEGER DEFAULT 1, 
                 notifications TEXT DEFAULT 'homework,changes,announcements',
                 blocked_until TEXT DEFAULT NULL)''')

    c.execute('''CREATE TABLE IF NOT EXISTS admins
                 (id INTEGER PRIMARY KEY, role TEXT DEFAULT 'admin')''')

    # Инициализация расписания
    c.execute("DELETE FROM schedule")
    times = ["8:30 - 10:00", "10:10 - 11:40", "12:30 - 14:00", "14:10 - 15:40", "15:50 - 17:20", "17:30 - 19:00"]
    directions = ['Ф', 'У', 'ФМ', 'ГМУ', 'БИ']

    schedule_bi = {
        "чётная": {
            "Понедельник": ["Матем (л) (222)", "Матем (с) (222)", "Физ-ра", "Англ (209)", "", ""],
            "Вторник": ["История (с) (108)", "История (л) (108)", "ИТПД (с) (217)", "", "", ""],
            "Среда": ["", "", "", "ИТПД (с) (217)", "Phython (л) (111)", "Phython (л) (111)"],
            "Четверг": ["", "История (с) (204)", "Менеджмент (л) (209)", "", "", ""],
            "Пятница": ["", "", "", "БЖД (л) (304)", "Менеджмент (с) (108)", "Физ-ра"]
        },
        "нечётная": {
            "Понедельник": ["Матем (л) (222)", "Матем (с) (222)", "Физ-ра", "Англ (209)", "", ""],
            "Вторник": ["Англ (209)", "История (л) (108)", "ИТПД (с) (217)", "История ФУ (л) (211)", "", ""],
            "Среда": ["", "", "", "ИТПД (с) (217)", "Введение в спец (л) (111)", "Phython (с) (111)"],
            "Четверг": ["Введение в спец (с) (213)", "Матем (с) (204)", "История (с) (209)", "", "", ""],
            "Пятница": ["", "", "", "БЖД (с) (304)", "Менеджмент (с) (108)", "Физ-ра"]
        }
    }

    for course in range(1, 5):
        for direction in directions:
            schedule_data = {
                "чётная": {day: [""] * 6 for day in ["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"]},
                "нечётная": {day: [""] * 6 for day in ["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"]}
            }

            if direction == 'БИ' and course == 1:
                schedule_data = schedule_bi
            else:
                for week_type, days in schedule_data.items():
                    for day in days:
                        days[day][0] = f"Курс {course}, Группа {direction}"

            for week_type, days in schedule_data.items():
                for day, slots in days.items():
                    for slot in range(6):
                        time = times[slot]
                        detail = slots[slot]
                        c.execute("INSERT INTO schedule (course, direction, week_type, day, slot, time, details) VALUES (?, ?, ?, ?, ?, ?, ?)",
                                  (course, direction, week_type, day, slot + 1, time, detail))

    conn.commit()
    conn.close()

def get_day_name(index):
    days_rus = [
        "Понедельник",
        "Вторник",
        "Среда",
        "Четверг",
        "Пятница",
        "Суббота",
        "Воскресенье"
    ]
    return days_rus[index]

def is_even_week(date):
    week_number = date.isocalendar()[1]
    return week_number % 2 == 0

def get_week_type(date):
    return 'чётная' if is_even_week(date) else 'нечётная'

def get_week_type_short(date):
    return 'чёт' if is_even_week(date) else 'нечёт'

def get_schedule_for_day(course, direction, day_name, date):
    week_type = get_week_type(date)
    conn = sqlite3.connect('university.db')
    c = conn.cursor()

    c.execute(
        "SELECT slot, time, details FROM schedule WHERE course = ? AND direction = ? AND week_type = ? AND day = ? ORDER BY slot",
        (course, direction, week_type, day_name)
    )
    results = c.fetchall()
    conn.close()

    if not results:
        return "Нет занятий"

    day_schedule = ""
    for slot, time, details in results:
        if details:
            day_schedule += f"{slot}. {time}\n{details}\n\n"

    return day_schedule.strip() if day_schedule else "Нет занятий"

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    user_id = update.effective_user.id

    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT blocked_until FROM users WHERE id=?", (user_id,))
    blocked_until = c.fetchone()

    if blocked_until and blocked_until[0]:
        blocked_until_date = datetime.fromisoformat(blocked_until[0])
        if blocked_until_date > datetime.now():
            await update.message.reply_text(f"Вы заблокированы! До разблокировки {blocked_until_date}.")
            conn.close()
            return

    conn.close()

    await update.message.reply_text('Привет! Поменяй группу и курс на соответствующие в своём личном кабинете.')
    await personal_cabinet(update, context)

    keyboard = [
        ["Выбрать дату расписания", "Расписание на завтра", "Расписание на сегодня"],
        ["Понедельник", "Вторник", "Среда"],
        ["Четверг", "Пятница", "Суббота"],
        ["Личный кабинет"]
    ]

    reply_markup = ReplyKeyboardMarkup(keyboard, one_time_keyboard=True, resize_keyboard=True)

    # Удалено сообщение 'Выбери опцию:'
    await update.message.reply_text(reply_markup=reply_markup)

async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    user_id = update.message.from_user.id

    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT blocked_until FROM users WHERE id=?", (user_id,))
    blocked_until = c.fetchone()

    if blocked_until and blocked_until[0]:
        blocked_until_date = datetime.fromisoformat(blocked_until[0])
        if blocked_until_date > datetime.now():
            await update.message.reply_text(f"Вы заблокированы! До разблокировки {blocked_until_date}.")
            conn.close()
            return

    conn.close()

    user_message = update.message.text.strip().lower()
    logging.info(f"Received message: {user_message}")

    user_states = context.user_data
    logging.info(f"User states: {user_states}")

    if context.user_data.get('awaiting_date', False):
        if user_message.isdigit():
            day = int(user_message)
            current_month = datetime.now(pytz.timezone('Asia/Omsk')).month
            current_year = datetime.now(pytz.timezone('Asia/Omsk')).year
            try:
                date_obj = datetime(current_year, current_month, day, tzinfo=pytz.timezone('Asia/Omsk'))
                if date_obj.month != current_month:
                    raise ValueError
                await show_schedule_by_date(update, context, date_obj)
            except ValueError:
                await update.message.reply_text('Неверный день. Пожалуйста, введи число от 1 до последнего дня месяца.')
            finally:
                context.user_data['awaiting_date'] = False
        else:
            await update.message.reply_text('Пожалуйста, введи число для получения расписания.')
        return

    if user_message in ["расписание на сегодня", "расписание на завтра", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"]:
        await show_schedule(update, context, user_message)

    elif user_message == "выбрать дату расписания":
        logging.info("User chose to select a specific date for schedule")
        context.user_data['awaiting_date'] = True
        await update.message.reply_text("Введи необходимое число этого месяца:")

    elif user_message == "личный кабинет":
        logging.info("User accessing personal cabinet")
        await personal_cabinet(update, context)

    else:
        logging.warning(f"Unrecognized menu option: {user_message}")
        await update.message.reply_text('Выбери опцию из меню.')

async def personal_cabinet(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id
    username = update.effective_user.username
    first_name = update.effective_user.first_name
    last_name = update.effective_user.last_name or ""

    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT username, course, direction, subscribed, notifications FROM users WHERE id = ?", (user_id,))
    user = c.fetchone()

    if not user:
        c.execute("INSERT INTO users (id, username, course, direction) VALUES (?, ?, ?, ?)", (user_id, username, 1, "Ф"))
        conn.commit()
        user = (username, 1, "Ф", 1, 'homework,changes,announcements')

    c.execute("SELECT 1 FROM admins WHERE id = ?", (user_id,))
    is_admin = c.fetchone() is not None

    conn.close()

    current_date = datetime.now(pytz.timezone('Asia/Omsk'))
    week_number = current_date.isocalendar()[1]
    week_type = get_week_type(current_date)
    week_status = f"{week_number} {week_type}"

    role = "Преподаватель" if is_admin else "Студент"
    subscribe_state = "Отписаться от уведомлений" if user[3] else "Подписаться на уведомления"

    message_text = (
        f"Личный кабинет\n\n"
        f"Имя: {first_name} {last_name}\n"
        f"Ник: @{user[0]}\n"
        f"ID: {user_id}\n\n"
        f"Роль: {role}\n"
        f"Группа: {user[2]}\n"
        f"Курс: {user[1]}\n\n"
        f"Неделя: {week_status}\n"
        f"Дата: {current_date.strftime('%d.%m.%Y')}\n"
        f"Время: {current_date.strftime('%H:%M:%S')}"
    )

    keyboard = [
        [
            InlineKeyboardButton("Изменить группу", callback_data='change_direction'),
            InlineKeyboardButton("Изменить курс", callback_data='change_course')
        ],
        [InlineKeyboardButton("Уведомления", callback_data='manage_notifications')],
    ]

    if is_admin:
        keyboard.append([
            InlineKeyboardButton("Статистика", callback_data='show_statistics'),
            InlineKeyboardButton("Сделать рассылку", callback_data='send_announcement'),
            InlineKeyboardButton("Глобальная рассылка", callback_data='send_global_announcement'),
            InlineKeyboardButton("Заблокировать", callback_data='block_user'),
            InlineKeyboardButton("Разблокировать", callback_data='unblock_user'),
            InlineKeyboardButton("Лист заблокированных", callback_data='view_blocked_users'),
        ])

    if user_id == MAIN_ADMIN_ID:
        keyboard.append([InlineKeyboardButton("Назначить администратора", callback_data='promote_admin')])

    reply_markup = InlineKeyboardMarkup(keyboard)

    if update.callback_query:
        await update.callback_query.edit_message_text(text=message_text, reply_markup=reply_markup)
    else:
        await update.message.reply_text(text=message_text, reply_markup=reply_markup)

async def handle_callback(update: Update, context: CallbackContext):
    query = update.callback_query
    user_id = query.from_user.id
    conn = sqlite3.connect('university.db')
    c = conn.cursor()

    try:
        if query.data == 'change_course':
            c.execute("SELECT course FROM users WHERE id = ?", (user_id,))
            current_course = c.fetchone()[0]
            new_course = 1 if current_course == 4 else current_course + 1
            c.execute("UPDATE users SET course = ? WHERE id = ?", (new_course, user_id))
            conn.commit()
            await query.answer(f"Курс изменён на {new_course}")
            await personal_cabinet(update, context)

        elif query.data == 'change_direction':
            c.execute("SELECT direction FROM users WHERE id = ?", (user_id,))
            current_direction = c.fetchone()[0]
            directions = ['Ф', 'У', 'ФМ', 'ГМУ', 'БИ']
            new_direction_index = (directions.index(current_direction) + 1) % len(directions)
            new_direction = directions[new_direction_index]
            c.execute("UPDATE users SET direction = ? WHERE id = ?", (new_direction, user_id))
            conn.commit()
            await query.answer(f"Группа изменена на {new_direction}")
            await personal_cabinet(update, context)

        elif query.data == 'toggle_subscription':
            c.execute("SELECT subscribed FROM users WHERE id = ?", (user_id,))
            current_subscription = c.fetchone()[0]
            new_subscription = 0 if current_subscription else 1
            c.execute("UPDATE users SET subscribed = ? WHERE id = ?", (new_subscription, user_id))
            conn.commit()
            await query.answer("Подписка обновлена")
            await personal_cabinet(update, context)

        elif query.data == 'send_announcement' and is_admin_user(user_id):
            c.execute("SELECT course, direction FROM users WHERE id = ?", (user_id,))
            admin_info = c.fetchone()
            context.user_data['announcement_for'] = admin_info[:2]  # course, direction
            context.user_data['is_sending_announcement'] = True
            context.user_data['is_sending_photo'] = False
            await query.answer("Введите сообщение для рассылки вашей группе")

        elif query.data == 'send_global_announcement' and is_admin_user(user_id):
            context.user_data['announcement_for'] = 'global'
            context.user_data['is_sending_announcement'] = True
            context.user_data['is_sending_photo'] = False
            await query.answer("Введите сообщение для глобальной рассылки")

        elif query.data == 'confirm_send':
            await send_announcement(context, include_photo=context.user_data.get('is_sending_photo', False))
            await update.callback_query.edit_message_text("Успешная отправка.")
            context.user_data['announcement_for'] = None
            context.user_data['is_sending_photo'] = False
            await query.answer("Рассылка отправлена.")

        elif query.data == 'cancel_send':
            await update.callback_query.edit_message_text("Отправка отменена.")
            context.user_data['announcement_for'] = None
            context.user_data['is_sending_photo'] = False
            await query.answer("Рассылка отменена.")

        elif query.data == 'show_statistics' and is_admin_user(user_id):
            await show_statistics(update, context)
        
        elif query.data == 'manage_notifications':
            await manage_notifications(update, user_id)

        elif query.data == 'block_user':
            context.user_data['action'] = 'block_user'
            await query.answer("Введите ID пользователя, которого хотите заблокировать.")

        elif query.data == 'unblock_user':
            context.user_data['action'] = 'unblock_user'
            await query.answer("Введите ID пользователя для разблокировки.")
        
        elif query.data == 'view_blocked_users':
            await view_blocked_users(update, context)
        
        elif query.data == 'promote_admin' and user_id == MAIN_ADMIN_ID:
            context.user_data['action'] = 'promote_admin'
            await query.answer("Введите ID пользователя, которого вы хотите сделать администратором.")

        elif query.data.startswith('page'):
            page_number = int(query.data.split('-')[1])
            await view_blocked_users(update, context, page_number=page_number)

        elif query.data.startswith("toggle_"):
            notification_type = query.data.split("_")[1]
            await toggle_notification(update, user_id, notification_type)

    finally:
        conn.close()

async def collect_announcement(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if not context.user_data.get('is_sending_announcement', False):
        return

    if update.message.photo:
        context.user_data['photo'] = update.message.photo[-1]  # Берём последнюю (наиболее детализированную)
        context.user_data['is_sending_photo'] = True

    message_text = update.message.caption if update.message.caption else update.message.text
    if not message_text:
        return

    context.user_data['message_text'] = message_text
    context.user_data['is_sending_announcement'] = False

    confirm_message = f"Вот ваш текст:\n\n{message_text}\n\nХотите отправить?"
    buttons = [
        [
            InlineKeyboardButton("Да", callback_data='confirm_send'),
            InlineKeyboardButton("Нет", callback_data='cancel_send')
        ]
    ]
    reply_markup = InlineKeyboardMarkup(buttons)

    await update.message.reply_text(confirm_message, reply_markup=reply_markup)

async def send_announcement(context: ContextTypes.DEFAULT_TYPE, include_photo=False):
    announcement_for = context.user_data.get('announcement_for')
    message_text = context.user_data.get('message_text')

    if not announcement_for or not message_text:
        return

    context.user_data['announcement_for'] = None
    context.user_data['message_text'] = None

    conn = sqlite3.connect('university.db')
    c = conn.cursor()

    if announcement_for == 'global':
        c.execute("SELECT id FROM users WHERE subscribed = 1")
        subscribers = c.fetchall()
        c.execute("SELECT id FROM admins")
        admins = c.fetchall()
    else:
        course, direction = announcement_for
        c.execute("SELECT id FROM users WHERE course = ? AND direction = ? AND subscribed = 1", (course, direction))
        subscribers = c.fetchall()
        c.execute("SELECT id FROM admins")
        admins = c.fetchall()

    conn.close()

    all_recipients = set(subscribers) | set(admins)

    for recipient in all_recipients:
        try:
            if include_photo and context.user_data.get('photo'):
                await context.bot.send_photo(chat_id=recipient[0], photo=context.user_data['photo'].file_id, caption=message_text)
            else:
                await context.bot.send_message(chat_id=recipient[0], text=message_text)
        except Exception as e:
            logging.error(f"Failed to send message to user {recipient[0]}: {e}")

def is_admin_user(user_id):
    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT role FROM admins WHERE id = ?", (user_id,))
    result = c.fetchone()
    conn.close()
    return result is not None

async def manage_notifications(update: Update, user_id):
    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT notifications FROM users WHERE id = ?", (user_id,))
    current_notifications = c.fetchone()[0].split(',')

    notification_types = ['homework', 'changes', 'announcements']
    buttons = []

    for n_type in notification_types:
        enabled = n_type in current_notifications
        text = f"{n_type.capitalize()}: {'✅' if enabled else '❌'}"
        buttons.append([InlineKeyboardButton(text, callback_data=f"toggle_{n_type}")])

    buttons.append([InlineKeyboardButton("Подписка на общие уведомления", callback_data="toggle_subscription")])

    reply_markup = InlineKeyboardMarkup(buttons)
    await update.callback_query.edit_message_text("Выберите типы уведомлений:", reply_markup=reply_markup)

async def toggle_notification(update: Update, user_id, notification_type):
    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT notifications FROM users WHERE id = ?", (user_id,))
    current_notifications = c.fetchone()[0].split(',')

    if notification_type in current_notifications:
        current_notifications.remove(notification_type)
    else:
        current_notifications.append(notification_type)

    c.execute("UPDATE users SET notifications = ? WHERE id = ?", (','.join(current_notifications), user_id))
    conn.commit()
    conn.close()
    await manage_notifications(update, user_id)

async def view_blocked_users(update: Update, context: ContextTypes.DEFAULT_TYPE, page_number=0):
    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT username, id, blocked_until FROM users WHERE blocked_until IS NOT NULL AND blocked_until > date('now')")
    blocked_users = c.fetchall()
    conn.close()

    items_per_page = 20
    start_index = page_number * items_per_page
    end_index = min(start_index + items_per_page, len(blocked_users))

    blocked_list = blocked_users[start_index:end_index]

    message_text = "Заблокированные пользователи:\n\n"
    for i, user in enumerate(blocked_list, start=start_index + 1):
        blocked_until = datetime.fromisoformat(user[2])
        time_left = str(blocked_until - datetime.now()).split('.')[0]
        message_text += f"{i}. {user[0]} - @{user[1]}\nДо разблокировки: {time_left}\n\n"

    total_pages = (len(blocked_users) + items_per_page - 1) // items_per_page

    buttons = [
        [
            InlineKeyboardButton("⬅️ Назад", callback_data=f"page-{page_number-1}") if page_number > 0 else InlineKeyboardButton("⬅️ Назад", callback_data='noop'),
            InlineKeyboardButton(f"{page_number + 1}/{total_pages}", callback_data='noop'),
            InlineKeyboardButton("Вперёд ➡️", callback_data=f"page-{page_number+1}") if end_index < len(blocked_users) else InlineKeyboardButton("Вперёд ➡️", callback_data='noop'),
        ]
    ]

    reply_markup = InlineKeyboardMarkup(buttons)
    await update.callback_query.edit_message_text(message_text.strip(), reply_markup=reply_markup)

async def show_schedule(update: Update, context: ContextTypes.DEFAULT_TYPE, day_command: str):
    user_id = update.message.from_user.id

    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT course, direction FROM users WHERE id = ?", (user_id,))
    user_info = c.fetchone()

    if not user_info:
        await personal_cabinet(update, context)
        c.execute("SELECT course, direction FROM users WHERE id = ?", (user_id,))
        user_info = c.fetchone()

        if not user_info:
            await update.message.reply_text("Ошибка при добавлении пользователя в базу данных.")
            return

    course, direction = user_info
    conn.close()

    current_date = datetime.now(pytz.timezone('Asia/Omsk'))
    current_weekday = current_date.weekday()

    days_map = {
        "расписание на сегодня": 0,
        "расписание на завтра": 1,
        "понедельник": 0,
        "вторник": 1,
        "среда": 2,
        "четверг": 3,
        "пятница": 4,
        "суббота": 5
    }
    day_index = days_map[day_command.lower()]

    if day_command.lower() == "расписание на сегодня":
        target_date = current_date
    elif day_command.lower() == "расписание на завтра":
        target_date = current_date + timedelta(days=1)
    else:
        day_offset = (day_index - current_weekday) % 7
        target_date = current_date + timedelta(days=day_offset)

    day_name = get_day_name(target_date.weekday())
    week_type_short = get_week_type_short(target_date)
    day_schedule = get_schedule_for_day(course, direction, day_name, target_date)

    message_text = f"{day_name} {target_date.strftime('%d.%m.%Y')} ({week_type_short}):\n\n{day_schedule}"
    await update.message.reply_text(message_text)

async def show_schedule_by_date(update: Update, context: ContextTypes.DEFAULT_TYPE, date_obj):
    user_id = update.message.from_user.id

    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    c.execute("SELECT course, direction FROM users WHERE id = ?", (user_id,))
    user_info = c.fetchone()

    if not user_info:
        await personal_cabinet(update, context)
        c.execute("SELECT course, direction FROM users WHERE id = ?", (user_id,))
        user_info = c.fetchone()

        if not user_info:
            await update.message.reply_text("Ошибка при добавлении пользователя в базу данных.")
            return

    course, direction = user_info
    conn.close()

    day_name = get_day_name(date_obj.weekday())
    week_type_short = get_week_type_short(date_obj)
    day_schedule = get_schedule_for_day(course, direction, day_name, date_obj)

    message_text = f"{day_name} {date_obj.strftime('%d.%m.%Y')} ({week_type_short}):\n\n{day_schedule}"
    await update.message.reply_text(message_text)

async def show_statistics(update: Update, context: ContextTypes.DEFAULT_TYPE):
    if not is_admin_user(update.effective_user.id):
        await update.callback_query.answer("Нет доступа!")
        return
    
    conn = sqlite3.connect('university.db')
    c = conn.cursor()

    # Общее количество пользователей
    c.execute("SELECT COUNT(*) FROM users")
    total_users = c.fetchone()[0]

    # Новые пользователи за сегодня
    c.execute("SELECT COUNT(*) FROM users WHERE DATE((SELECT DATETIME('now', 'localtime'))) = DATE(('now'))")
    new_users_today = c.fetchone()[0]

    # Новые пользователи за вчера
    c.execute("SELECT COUNT(*) FROM users WHERE DATE((SELECT DATETIME('now', 'localtime', '-1 day'))) = DATE(('now'))")
    new_users_yesterday = c.fetchone()[0]

    # Активные пользователи за сегодня
    current_date = datetime.now(pytz.timezone('Asia/Omsk'))
    c.execute("SELECT COUNT(DISTINCT id) FROM users WHERE id IN (SELECT DISTINCT id FROM schedule WHERE day = ?)", (get_day_name(current_date.weekday()),))
    active_today = c.fetchone()[0]

    # Активные пользователи за вчера
    yesterday_date = current_date - timedelta(days=1)
    c.execute("SELECT COUNT(DISTINCT id) FROM users WHERE id IN (SELECT DISTINCT id FROM schedule WHERE day = ?)", (get_day_name(yesterday_date.weekday()),))
    active_yesterday = c.fetchone()[0]
    
    # Самая активная группа
    c.execute("SELECT course, direction, COUNT(*) as message_count FROM schedule GROUP BY course, direction ORDER BY message_count DESC LIMIT 1")
    most_active_group = c.fetchone()

    conn.close()

    stats_message = (
        f"Статистика:\n\n"
        f"Всего пользователей: {total_users}\n"
        f"Новых пользователей сегодня: {new_users_today}\n"
        f"Новых пользователей вчера: {new_users_yesterday}\n"
        f"Активных пользователей сегодня: {active_today}\n"
        f"Активных пользователей вчера: {active_yesterday}\n"
        f"Самая активная группа: Курс {most_active_group[0]}, Направление {most_active_group[1]} с {most_active_group[2]} сообщениями.\n"
    )
    await update.callback_query.edit_message_text(stats_message)

if __name__ == '__main__':
    # Создание конфигурационного файла, если он не существует
    if not os.path.exists('config.ini'):
        create_config_file()
        print("Please edit config.ini and set the bot token")
        exit(1)

    init_db()

    application = ApplicationBuilder().token(TOKEN).build()

    application.add_handler(CommandHandler("start", start))
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
    application.add_handler(CallbackQueryHandler(handle_callback))
    application.add_handler(MessageHandler(filters.PHOTO, collect_announcement))  # Обработка отправки фотографий

    application.run_polling()

Что мне не нравится в нём:
Вместо "Подписка на общие уведомления" поставь кнопку назад. А кнопки выше сделай на русском. Домашнее задание. Изменения в расписании. Оповещения группы. Оповещения университета. Должно быть 4 кнопки + кнопка назад