Вот ошибка: Traceback (most recent call last):
  File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in <module>    start(fakepyfile,mainpyfile)
  File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start
    exec(open(mainpyfile).read(),  __main__.__dict__)
  File "<string>", line 603
    async def collect_mailing_message(update: Update, context: CallbackContext) -> None:
SyntaxError: expected 'except' or 'finally' block

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

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

# Чтение конфигурационного файла
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()

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

    # Создание таблицы users с колонкой created_at
    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,university',
            blocked_until TEXT DEFAULT NULL,
            created_at TEXT DEFAULT (datetime('now','localtime'))
        )
    ''')

    # Создание таблицы teachers
    c.execute('''CREATE TABLE IF NOT EXISTS teachers
                 (id INTEGER PRIMARY KEY)''')

    # Добавить главного администратора в таблицу преподавателей
    c.execute("INSERT OR IGNORE INTO teachers (id) VALUES (?)", (MAIN_ADMIN_ID,))

    # Проверка и добавление колонки created_at, если таблица уже существует без неё
    c.execute("PRAGMA table_info(users)")
    columns = [info[1] for info in c.fetchall()]
    if 'created_at' not in columns:
        try:
            c.execute("ALTER TABLE users ADD COLUMN created_at TEXT DEFAULT (datetime('now','localtime'))")
            conn.commit()
            print("Колонка 'created_at' успешно добавлена в таблицу 'users'.")
        except sqlite3.OperationalError as e:
            print(f"Ошибка при добавлении колонки 'created_at': {e}")

    # Инициализация расписания
    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: CallbackContext) -> 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()

    # Генерация меню
    keyboard = [
        ["🗓 Выбрать дату расписания", "📅 Расписание на завтра", "📅 Расписание на сегодня"],
        ["📆 Понедельник", "📆 Вторник", "📆 Среда"],
        ["📆 Четверг", "📆 Пятница", "📆 Суббота"],
        ["👤 Личный кабинет"]
    ]
    reply_markup = ReplyKeyboardMarkup(keyboard, one_time_keyboard=True, resize_keyboard=True)
    
    # Приветственное сообщение с меню
    await update.message.reply_text(
        '👋 Привет! Поменяй группу и курс на соответствующие в своём личном кабинете.',
        reply_markup=reply_markup
    )
    
    # Отображение личного кабинета
    await personal_cabinet(update, context)

async def handle_message(update: Update, context: CallbackContext) -> None:
    user_id = update.message.from_user.id
    user_message = update.message.text.strip().lower()

    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

    # Обработка специальных действий
    if context.user_data.get('action') == 'promote_admin':
        try:
            promote_id = int(user_message)
            c.execute("SELECT id FROM users WHERE id = ?", (promote_id,))
            if not c.fetchone():
                await update.message.reply_text("❌ Пользователь с таким ID не найден.")
            else:
                c.execute("INSERT OR IGNORE INTO teachers (id) VALUES (?)", (promote_id,))
                conn.commit()
                await update.message.reply_text(f"✅ Пользователь с ID {promote_id} назначен администратором.")
        except ValueError:
            await update.message.reply_text("❌ Неверный формат ID. Пожалуйста, введите числовой ID пользователя.")
        except sqlite3.Error as e:
            logger.error(f"Ошибка при назначении администратора: {e}")
            await update.message.reply_text("❌ Произошла ошибка при назначении администратора.")
        finally:
            conn.close()
            context.user_data['action'] = None
        return

    if context.user_data.get('action') == 'demote_admin':
        try:
            demote_id = int(user_message)
            if demote_id == MAIN_ADMIN_ID:
                await update.message.reply_text("❌ Невозможно удалить главного администратора.")
            else:
                c.execute("SELECT id FROM teachers WHERE id = ?", (demote_id,))
                if not c.fetchone():
                    await update.message.reply_text("❌ Пользователь с таким ID не является администратором.")
                else:
                    c.execute("DELETE FROM teachers WHERE id = ?", (demote_id,))
                    conn.commit()
                    await update.message.reply_text(f"✅ Пользователь с ID {demote_id} удален из администраторов.")
        except ValueError:
            await update.message.reply_text("❌ Неверный формат ID. Пожалуйста, введите числовой ID пользователя.")
        except sqlite3.Error as e:
            logger.error(f"Ошибка при удалении администратора: {e}")
            await update.message.reply_text("❌ Произошла ошибка при удалении администратора.")
        finally:
            conn.close()
            context.user_data['action'] = None
        return

    if context.user_data.get('action') == 'block_user':
        try:
            block_id = int(user_message)
            c.execute("SELECT id FROM users WHERE id = ?", (block_id,))
            if not c.fetchone():
                await update.message.reply_text("❌ Пользователь с таким ID не найден.")
            else:
                # Установим блокировку на 24 часа
                block_until = datetime.now() + timedelta(hours=24)
                c.execute("UPDATE users SET blocked_until = ? WHERE id = ?", (block_until.isoformat(), block_id))
                conn.commit()
                await update.message.reply_text(f"🔒 Пользователь с ID {block_id} заблокирован до {block_until}.")
        except ValueError:
            await update.message.reply_text("❌ Неверный формат ID. Пожалуйста, введите числовой ID пользователя.")
        except sqlite3.Error as e:
            logger.error(f"Ошибка при блокировке пользователя: {e}")
            await update.message.reply_text("❌ Произошла ошибка при блокировке пользователя.")
        finally:
            conn.close()
            context.user_data['action'] = None
        return

    if context.user_data.get('action') == 'unblock_user':
        try:
            unblock_id = int(user_message)
            if unblock_id == MAIN_ADMIN_ID:
                await update.message.reply_text("❌ Невозможно разблокировать главного администратора.")
                conn.close()
                context.user_data['action'] = None
                return

            c.execute("SELECT id FROM users WHERE id = ? AND blocked_until IS NOT NULL", (unblock_id,))
            if not c.fetchone():
                await update.message.reply_text("❌ Пользователь с таким ID не заблокирован.")
            else:
                c.execute("UPDATE users SET blocked_until = NULL WHERE id = ?", (unblock_id,))
                conn.commit()
                await update.message.reply_text(f"🔓 Пользователь с ID {unblock_id} разблокирован.")
        except ValueError:
            await update.message.reply_text("❌ Неверный формат ID. Пожалуйста, введите числовой ID пользователя.")
        except sqlite3.Error as e:
            logger.error(f"Ошибка при разблокировке пользователя: {e}")
            await update.message.reply_text("❌ Произошла ошибка при разблокировке пользователя.")
        finally:
            conn.close()
            context.user_data['action'] = None
        return

    conn.close()

    # Основная логика обработки сообщений
    logger.info(f"Received message: {user_message}")

    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 == "выбрать дату расписания":
        logger.info("User chose to select a specific date for schedule")
        context.user_data['awaiting_date'] = True
        await update.message.reply_text("🗓 Введи необходимое число этого месяца:")
    elif user_message == "личный кабинет":
        logger.info("User accessing personal cabinet")
        await personal_cabinet(update, context)
    else:
        logger.warning(f"Unrecognized menu option: {user_message}")
        await update.message.reply_text('❓ Выбери опцию из меню.')

async def personal_cabinet(update: Update, context: CallbackContext):
    user_id = update.effective_user.id
    username = update.effective_user.username or ""
    first_name = update.effective_user.first_name or ""
    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:
        current_time = datetime.now(pytz.timezone('Asia/Omsk')).isoformat()
        c.execute(
            "INSERT INTO users (id, username, course, direction, created_at) VALUES (?, ?, ?, ?, ?)",
            (user_id, username, 1, "Ф", current_time)
        )
        conn.commit()
        user = (username, 1, "Ф", 1, 'homework,changes,announcements,university')

    # Проверка существования ID в таблице teachers, добавление, если его там нет
    c.execute("SELECT 1 FROM teachers WHERE id = ?", (user_id,))
    is_teacher = c.fetchone() is not None

    if user_id == MAIN_ADMIN_ID and not is_teacher:
        c.execute("INSERT INTO teachers (id) VALUES (?)", (user_id,))
        conn.commit()
        is_teacher = True

    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_teacher 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')}\n"
    )

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

    if is_teacher:
        buttons.append([InlineKeyboardButton("🔧 Для администраторов", callback_data='admin_panel')])

    reply_markup = InlineKeyboardMarkup(buttons)

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

async def admin_panel(update: Update, context: CallbackContext):
    query = update.callback_query
    user_id = query.from_user.id

    logger.info(f"Accessing admin panel - User ID: {user_id}")

    if not is_teacher_user(user_id):
        await query.answer("❌ Нет доступа!", show_alert=True)
        return

    buttons = [
        [InlineKeyboardButton("📈 Статистика", callback_data='show_statistics')],
        [InlineKeyboardButton("📢 Рассылки", callback_data='announcements_menu')],
        [InlineKeyboardButton("🔒 Блокировки", callback_data='blocking_menu')]
    ]

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

    # Добавим кнопку "Назад" для возвращения в личный кабинет
    buttons.append([InlineKeyboardButton("🔙 Назад", callback_data='personal_cabinet')])

    reply_markup = InlineKeyboardMarkup(buttons)
    await query.edit_message_text(text="🔧 **Для администраторов:**", reply_markup=reply_markup, parse_mode='Markdown')

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

    try:
        if data == 'change_course':
            c.execute("SELECT course FROM users WHERE id = ?", (user_id,))
            result = c.fetchone()
            if result:
                current_course = result[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)
            else:
                await query.answer("❌ Пользователь не найден.")

        elif data == 'change_direction':
            c.execute("SELECT direction FROM users WHERE id = ?", (user_id,))
            result = c.fetchone()
            if result:
                current_direction = result[0]
                directions = ['Ф', 'У', 'ФМ', 'ГМУ', 'БИ']
                try:
                    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)
                except ValueError:
                    await query.answer("❌ Некорректная текущая группа.")
            else:
                await query.answer("❌ Пользователь не найден.")

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

        elif data == 'manage_notifications':
            await manage_notifications(update, user_id)

        elif data == 'admin_panel':
            await admin_panel(update, context)

        elif data == 'show_statistics' and is_teacher_user(user_id):
            await show_statistics(update, context)

        # Меню рассылок
        elif data == 'announcements_menu' and is_teacher_user(user_id):
            # Меню рассылок
            buttons = [
                [InlineKeyboardButton("📤 Отправить рассылку", callback_data='send_announcement')],
                [InlineKeyboardButton("🗂 Глобальная рассылка", callback_data='send_global_announcement')],
                [InlineKeyboardButton("🔙 Назад", callback_data='admin_panel')]
            ]
            reply_markup = InlineKeyboardMarkup(buttons)
            await query.edit_message_text(text="📢 **Меню рассылок:**", reply_markup=reply_markup, parse_mode='Markdown')

        # Начало рассылки
        elif data == 'send_announcement' and is_teacher_user(user_id):
            # Выбор типа рассылки
            buttons = [
                [InlineKeyboardButton("📚 Домашнее задание", callback_data='mailing_homework')],
                [InlineKeyboardButton("🔄 Изменения в расписании", callback_data='mailing_changes')],
                [InlineKeyboardButton("📢 Оповещения группы", callback_data='mailing_announcements')],
                [InlineKeyboardButton("🏫 Оповещения университета", callback_data='mailing_university')],
                [InlineKeyboardButton("🔙 Назад", callback_data='announcements_menu')]
            ]
            reply_markup = InlineKeyboardMarkup(buttons)
            await query.edit_message_text(text="📤 **Выберите тип рассылки:**", reply_markup=reply_markup, parse_mode='Markdown')

        # Выбор типа рассылки для групповой отправки
        elif data.startswith('mailing_') and not data.startswith('mailing_target'):
            mailing_type = data.split('_')[1]
            context.user_data['mailing_type'] = mailing_type
            # Выбор целевой аудитории
            buttons = [
                [InlineKeyboardButton("📆 По курсу и группе", callback_data='mailing_target_group')],
                [InlineKeyboardButton("🔙 Назад", callback_data='send_announcement')]
            ]
            reply_markup = InlineKeyboardMarkup(buttons)
            await query.edit_message_text(text=f"📤 **Выбрано: {mailing_type.capitalize()}**\nВыберите целевую аудиторию рассылки:", reply_markup=reply_markup, parse_mode='Markdown')

        elif data == 'mailing_target_group' and is_teacher_user(user_id):
            # Запросить сообщение для рассылки
            await query.edit_message_text("📝 **Введите сообщение для рассылки вашей группе:**")
            context.user_data['awaiting_mailing_message'] = True

        elif data == 'send_global_announcement' and is_teacher_user(user_id):
            # Выбор типа глобальной рассылки
            buttons = [
                [InlineKeyboardButton("📚 Домашнее задание", callback_data='global_mailing_homework')],
                [InlineKeyboardButton("🔄 Изменения в расписании", callback_data='global_mailing_changes')],
                [InlineKeyboardButton("📢 Оповещения группы", callback_data='global_mailing_announcements')],
                [InlineKeyboardButton("🏫 Оповещения университета", callback_data='global_mailing_university')],
                [InlineKeyboardButton("🔙 Назад", callback_data='announcements_menu')]
            ]
            reply_markup = InlineKeyboardMarkup(buttons)
            await query.edit_message_text(text="🗂 **Выберите тип глобальной рассылки:**", reply_markup=reply_markup, parse_mode='Markdown')

        # Выбор типа рассылки для глобальной отправки
        elif data.startswith('global_mailing_') and is_teacher_user(user_id):
            mailing_type = data.split('_')[2]
            context.user_data['mailing_type'] = mailing_type
            context.user_data['mailing_target'] = 'global'
            # Запросить сообщение для глобальной рассылки
            await query.edit_message_text("📝 **Введите сообщение для глобальной рассылки:**")
            context.user_data['awaiting_mailing_message'] = True

        # Меню блокировок
        elif data == 'blocking_menu' and is_teacher_user(user_id):
            # Меню блокировок
            buttons = [
                [InlineKeyboardButton("🔒 Заблокировать пользователя", callback_data='block_user')],
                [InlineKeyboardButton("🔓 Разблокировать пользователя", callback_data='unblock_user')],
                [InlineKeyboardButton("👤 Просмотреть заблокированных пользователей", callback_data='view_blocked_users')],
                [InlineKeyboardButton("🔙 Назад", callback_data='admin_panel')]
            ]
            reply_markup = InlineKeyboardMarkup(buttons)
            await query.edit_message_text(text="🔒 **Меню блокировок:**", reply_markup=reply_markup, parse_mode='Markdown')

        # Просмотр заблокированных пользователей
        elif data == 'view_blocked_users' and is_teacher_user(user_id):
            await view_blocked_users(update, context)

        elif data.startswith('page-') and is_teacher_user(user_id):
            # Обработка пагинации заблокированных пользователей
            try:
                page_number = int(data.split('-')[1])
                await view_blocked_users(update, context, page_number=page_number)
            except (IndexError, ValueError):
                await query.answer("❌ Неверный номер страницы.", show_alert=True)

        elif data == 'personal_cabinet' or data == 'back_to_admin':
            await personal_cabinet(update, context)

        else:
            await query.answer("❓ Неизвестная команда.", show_alert=True)

async def collect_mailing_message(update: Update, context: CallbackContext) -> None:
    user_id = update.message.from_user.id
    if not is_teacher_user(user_id) or not context.user_data.get('awaiting_mailing_message', False):
        return

    mailing_type = context.user_data.get('mailing_type')
    mailing_target = context.user_data.get('mailing_target', 'group')
    message_text = update.message.text

    if not message_text:
        await update.message.reply_text("❌ Сообщение не может быть пустым.")
        return

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

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

    await update.message.reply_text(confirm_message, reply_markup=reply_markup, parse_mode='Markdown')

async def handle_mailing_confirm(update: Update, context: CallbackContext) -> None:
    query = update.callback_query
    user_id = query.from_user.id
    data = query.data

    if data == 'confirm_send_mailing':
        await send_mailing(update, context)
        await query.edit_message_text("✅ Рассылка успешно отправлена.")
    elif data == 'cancel_send_mailing':
        await query.edit_message_text("❌ Отправка рассылки отменена.")
    else:
        await query.answer("❓ Неизвестная команда.")

async def send_mailing(update: Update, context: CallbackContext) -> None:
    mailing_type = context.user_data.get('mailing_type')
    mailing_target = context.user_data.get('mailing_target', 'group')
    message_text = context.user_data.get('message_text')

    if not mailing_type or not message_text:
        return

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

    try:
        if mailing_target == 'global':
            # Получаем только пользователей, подписанных на данный тип рассылки
            c.execute("SELECT id FROM users WHERE subscribed = 1 AND notifications LIKE ?", (f'%{mailing_type}%',))
            users = c.fetchall()
            # Включаем администраторов
            c.execute("SELECT id FROM teachers")
            admins = c.fetchall()
            recipients = set(users) | set(admins)
        elif mailing_target == 'group':
            # Получаем курс и группу отправителя
            c.execute("SELECT course, direction FROM users WHERE id = ?", (update.effective_user.id,))
            user_info = c.fetchone()
            if not user_info:
                logger.error("Информация о пользователе не найдена для рассылки по группе.")
                return
            course, direction = user_info
            c.execute("SELECT id FROM users WHERE course = ? AND direction = ? AND subscribed = 1 AND notifications LIKE ?", 
                      (course, direction, f'%{mailing_type}%'))
            users = c.fetchall()
            # Включаем администраторов
            c.execute("SELECT id FROM teachers")
            admins = c.fetchall()
            recipients = set(users) | set(admins)
        else:
            logger.error(f"Неизвестный тип целевой аудитории рассылки: {mailing_target}")
            return

    except sqlite3.Error as e:
        logger.error(f"Ошибка при получении получателей рассылки: {e}")
        return
    finally:
        conn.close()

    # Отправка сообщений
    for recipient in recipients:
        try:
            await context.bot.send_message(chat_id=recipient[0], text=message_text)
        except Exception as e:
            logger.error(f"Не удалось отправить сообщение пользователю {recipient[0]}: {e}")

    # Очистка context
    context.user_data['mailing_type'] = None
    context.user_data['mailing_target'] = None
    context.user_data['message_text'] = None

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

        notification_map = {
            'homework': '📚 Домашнее задание',
            'changes': '🔄 Изменения в расписании',
            'announcements': '📢 Оповещения группы',
            'university': '🏫 Оповещения университета'
        }

        buttons = []

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

        buttons.append([InlineKeyboardButton("🔙 Назад", callback_data="personal_cabinet")])

        reply_markup = InlineKeyboardMarkup(buttons)
        await update.callback_query.edit_message_text("📌 **Выберите типы уведомлений:**", reply_markup=reply_markup, parse_mode='Markdown')
    except sqlite3.Error as e:
        logger.error(f"Ошибка при управлении уведомлениями: {e}")
        await update.callback_query.edit_message_text("❌ Произошла ошибка при управлении уведомлениями.")
    finally:
        conn.close()

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

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

        updated_notifications = ','.join(current_notifications)
        c.execute("UPDATE users SET notifications = ? WHERE id = ?", (updated_notifications, user_id))
        conn.commit()
    except sqlite3.Error as e:
        logger.error(f"Ошибка при переключении уведомления '{notification_type}': {e}")
        await update.callback_query.answer("❌ Произошла ошибка при изменении уведомлений.", show_alert=True)
        return
    finally:
        conn.close()
    
    await manage_notifications(update, user_id)

async def view_blocked_users(update: Update, context: CallbackContext, page_number=0):
    conn = sqlite3.connect('university.db')
    c = conn.cursor()
    try:
        c.execute(
            "SELECT username, id, blocked_until FROM users WHERE blocked_until IS NOT NULL AND blocked_until > datetime('now','localtime')"
        )
        blocked_users = c.fetchall()
    except sqlite3.Error as e:
        logger.error(f"Ошибка при получении заблокированных пользователей: {e}")
        await update.callback_query.edit_message_text("❌ Произошла ошибка при получении заблокированных пользователей.")
        return
    finally:
        conn.close()

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

    if total_pages == 0:
        await update.callback_query.edit_message_text("🔒 **Заблокированные пользователи отсутствуют.**")
        return

    if page_number < 0 or page_number >= total_pages:
        await update.callback_query.edit_message_text("❗ Неверный номер страницы.")
        return

    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 = f"🔒 **Заблокированные пользователи (Страница {page_number + 1}/{total_pages}):**\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"

    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 page_number + 1 < total_pages else InlineKeyboardButton("Вперёд ➡️", callback_data='noop'),
        ],
        [InlineKeyboardButton("🔙 Назад", callback_data='blocking_menu')]
    ]

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

def is_teacher_user(user_id):
    if user_id == MAIN_ADMIN_ID:
        return True

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

if __name__ == '__main__':
    # Создание конфигурационного файла, если он не существует
    if not os.path.exists('config.ini'):
        create_config_file()
        print("📄 Пожалуйста, отредактируйте config.ini и установите токен бота.")
        exit(1)

    init_db()

    # Создание и инициализация объекта application
    application = ApplicationBuilder().token(TOKEN).build()

    # Добавление обработчиков команд и сообщений
    application.add_handler(CommandHandler("start", start))
    application.add_handler(CallbackQueryHandler(handle_callback, pattern='^.*$'))
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
    application.add_handler(MessageHandler(filters.TEXT & filters.Regex('^.*$'), collect_mailing_message))
    application.add_handler(MessageHandler(filters.PHOTO, collect_mailing_message))
    # Обработчик для подтверждения рассылки
    application.add_handler(CallbackQueryHandler(handle_mailing_confirm, pattern='^(confirm_send_mailing|cancel_send_mailing)$'))
    
    # Запуск бота
    application.run_polling(). Помоги мне и реши проблемы с ошибкой. Вышли полный код