Загрузка...

SupportBot

Тема в разделе Python создана пользователем 0О0 12 май 2025. (поднята 21 май 2025) 193 просмотра

Загрузка...
  1. 0О0
    0О0 Автор темы 12 май 2025 lolz.live/threads/11111/ - Работайте с лучшими. 629 1 май 2022
    Python
    import asyncio
    from datetime import datetime, timedelta
    from aiogram import Bot, Dispatcher, Router, F
    from aiogram.enums import ParseMode
    from aiogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup
    from aiogram.filters import CommandStart, Command
    from aiogram.fsm.storage.memory import MemoryStorage
    import aiosqlite

    TOKEN = 'YOUR_BOT_TOKEN' # Вставь сюда токен
    CHANNEL_ID = -1001234567890 # Вставь ID канала
    ADMINS = [123456789] # Вставь ID админов

    bot = Bot(token=TOKEN, parse_mode=ParseMode.HTML)
    dp = Dispatcher(storage=MemoryStorage())
    router = Router()
    dp.include_router(router)


    async def init_db():
    async with aiosqlite.connect("bot.db") as db:
    await db.execute("""
    CREATE TABLE IF NOT EXISTS tickets (
    user_id INTEGER,
    username TEXT,
    post_id INTEGER,
    is_closed INTEGER DEFAULT 0,
    created_at TEXT
    )""")
    await db.execute("""
    CREATE TABLE IF NOT EXISTS moderators (
    user_id INTEGER PRIMARY KEY
    )""")
    await db.commit()

    async def add_ticket(user_id, username, post_id):
    async with aiosqlite.connect("bot.db") as db:
    await db.execute("INSERT INTO tickets (user_id, username, post_id, created_at) VALUES (?, ?, ?, ?)",
    (user_id, username, post_id, datetime.utcnow().isoformat()))
    await db.commit()

    async def close_ticket(user_id):
    async with aiosqlite.connect("bot.db") as db:
    await db.execute("UPDATE tickets SET is_closed = 1 WHERE user_id = ?", (user_id,))
    await db.commit()

    async def get_stats():
    async with aiosqlite.connect("bot.db") as db:
    open_ = await db.execute_fetchone("SELECT COUNT(*) FROM tickets WHERE is_closed = 0")
    closed = await db.execute_fetchone("SELECT COUNT(*) FROM tickets WHERE is_closed = 1")
    return open_[0], closed[0]

    async def get_expired_tickets():
    expired_users = []
    async with aiosqlite.connect("bot.db") as db:
    cursor = await db.execute("SELECT user_id, created_at FROM tickets WHERE is_closed = 0")
    rows = await cursor.fetchall()
    for user_id, created_at in rows:
    created = datetime.fromisoformat(created_at)
    if datetime.utcnow() - created > timedelta(hours=47):
    expired_users.append(user_id)
    return expired_users

    async def is_moderator(user_id):
    async with aiosqlite.connect("bot.db") as db:
    result = await db.execute_fetchone("SELECT 1 FROM moderators WHERE user_id = ?", (user_id,))
    return result is not None

    async def add_moderator(user_id):
    async with aiosqlite.connect("bot.db") as db:
    await db.execute("INSERT OR IGNORE INTO moderators (user_id) VALUES (?)", (user_id,))
    await db.commit()

    async def get_all_moderators():
    async with aiosqlite.connect("bot.db") as db:
    rows = await db.execute_fetchall("SELECT user_id FROM moderators")
    return [row[0] for row in rows]

    async def get_open_tickets():
    async with aiosqlite.connect("bot.db") as db:
    cursor = await db.execute("SELECT user_id, username, created_at FROM tickets WHERE is_closed = 0")
    return await cursor.fetchall()


    def user_keyboard():
    return InlineKeyboardMarkup(inline_keyboard=[
    [InlineKeyboardButton(text="Создать обращение", callback_data="create_ticket")]
    ])

    def admin_keyboard():
    return InlineKeyboardMarkup(inline_keyboard=[
    [InlineKeyboardButton(text="Создать обращение", callback_data="create_ticket")],
    [InlineKeyboardButton(text="Канал", url="https://t.me/yourchannel")],
    [InlineKeyboardButton(text="Админ-панель", callback_data="admin_menu")]
    ])

    def admin_menu_kb():
    return InlineKeyboardMarkup(inline_keyboard=[
    [InlineKeyboardButton(text="Статистика", callback_data="admin_stats")],
    [InlineKeyboardButton(text="Открытые обращения", callback_data="admin_open_tickets")],
    [InlineKeyboardButton(text="Закрыть все", callback_data="admin_close_all")],
    [InlineKeyboardButton(text="Добавить модератора", callback_data="admin_addmod")]
    ])


    @router.message(CommandStart())
    async def start_cmd(message: Message):
    is_mod = await is_moderator(message.from_user.id)
    if message.from_user.id in ADMINS or is_mod:
    kb = admin_keyboard()
    else:
    kb = user_keyboard()
    await message.answer("Добро пожаловать в SupportMasterBot! Что вы хотите сделать?", reply_markup=kb)

    @router.callback_query(F.data == "create_ticket")
    async def create_ticket(callback):
    await callback.message.answer("Пожалуйста, напишите ваше обращение текстом.")

    @router.message(F.text)
    async def handle_user_message(message: Message):
    if message.from_user.id in ADMINS:
    return
    post = await bot.send_message(
    CHANNEL_ID,
    f"Новое сообщение от <a href='tg://user?id={message.from_user.id}'>{message.from_user.full_name}</a>:\n\n{message.text}"
    )
    await add_ticket(message.from_user.id, message.from_user.username, post.message_id)
    await message.answer("Ваше сообщение отправлено. Ожидайте ответа.")
    notifiers = ADMINS + await get_all_moderators()
    for uid in notifiers:
    try:
    await bot.send_message(uid, f"Новое обращение от пользователя:\n\n{message.text}")
    except:
    pass

    @router.message(Command("admin"))
    async def admin_panel(message: Message):
    if message.from_user.id in ADMINS:
    await message.answer("Админ-панель:", reply_markup=admin_menu_kb())

    @router.callback_query(F.data == "admin_menu")
    async def open_admin_menu(callback):
    if callback.from_user.id in ADMINS:
    await callback.message.answer("Админ-панель:", reply_markup=admin_menu_kb())

    @router.callback_query(F.data == "admin_stats")
    async def stats_callback(callback):
    if callback.from_user.id in ADMINS:
    open_t, closed_t = await get_stats()
    await callback.message.answer(f"Открытых: {open_t}\nЗакрытых: {closed_t}")

    @router.callback_query(F.data == "admin_close_all")
    async def close_all_tickets(callback):
    if callback.from_user.id in ADMINS:
    async with aiosqlite.connect("bot.db") as db:
    await db.execute("UPDATE tickets SET is_closed = 1 WHERE is_closed = 0")
    await db.commit()
    await callback.message.answer("Все обращения закрыты.")

    @router.callback_query(F.data == "admin_addmod")
    async def prompt_add_mod(callback):
    if callback.from_user.id in ADMINS:
    await callback.message.answer("Отправьте команду:\n<b>/addmod &lt;user_id&gt;</b>")

    @router.message(Command("addmod"))
    async def add_mod_cmd(message: Message):
    if message.from_user.id in ADMINS:
    try:
    _, user_id = message.text.split()
    user_id = int(user_id)
    await add_moderator(user_id)
    await message.answer(f"Пользователь {user_id} добавлен как модератор.")
    except Exception:
    await message.answer("Использование: /addmod <user_id>")

    @router.callback_query(F.data == "admin_open_tickets")
    async def show_open_tickets(callback):
    uid = callback.from_user.id
    if uid not in ADMINS and not await is_moderator(uid):
    return
    tickets = await get_open_tickets()
    if not tickets:
    await callback.message.answer("Нет открытых обращений.")
    return
    for user_id, username, created_at in tickets:
    name = f"@{username}" if username else f"ID: {user_id}"
    date = created_at.split("T")[0]
    msg = f"<b>{name}</b>\nСоздано: {date}"
    btn = InlineKeyboardMarkup(inline_keyboard=[
    [InlineKeyboardButton(text="Закрыть", callback_data=f"close_{user_id}")]
    ])
    await callback.message.answer(msg, reply_markup=btn)

    @router.callback_query(F.data.startswith("close_"))
    async def close_ticket_by_button(callback):
    user_id = callback.from_user.id
    if user_id not in ADMINS and not await is_moderator(user_id):
    return
    try:
    target_uid = int(callback.data.split("_")[1])
    await close_ticket(target_uid)
    await callback.message.edit_text("Обращение закрыто.")
    try:
    await bot.send_message(target_uid, "Ваше обращение было закрыто модератором.")
    except:
    pass
    except Exception:
    await callback.message.answer("Ошибка при закрытии обращения.")

    # === АВТОМАТИЧЕСКОЕ ЗАКРЫТИЕ ===
    async def auto_close_loop():
    while True:
    expired = await get_expired_tickets()
    for user_id in expired:
    await close_ticket(user_id)
    try:
    await bot.send_message(user_id, "Ваше обращение было автоматически закрыто (через 47 часов).")
    except:
    pass
    for admin_id in ADMINS:
    try:
    await bot.send_message(admin_id, f"Обращение от пользователя {user_id} закрыто автоматически.")
    except:
    pass
    await asyncio.sleep(3600)


    async def main():
    await init_db()
    asyncio.create_task(auto_close_loop())
    await dp.start_polling(bot)

    if __name__ == "__main__":
    asyncio.run(main())
    Функции
    Для пользователей:
    • /start — кнопка Создать обращение
    • Обращение публикуется в канал + комментарии
    • Пользователь получает уведомление об отправке
    Для модераторов и админов:
    • Кнопка “Админ-панель”:
      • Статистика — кол-во открытых/закрытых обращений
      • Открытые обращения — список тикетов с кнопками [Закрыть]
      • Закрыть все — массовое закрытие тикетов
      • Добавить модератора — инструкция по /addmod <user_id>
    Дополнительно:
    • Уведомления о новых обращениях отправляются админам и модераторам
    • модераторы отвечают в комментариях канала
    • Авто-закрытие обращений через 47 часов
    • Только админы и модераторы могут писать в канал/обсуждение

    Писал данного бота для человека, человек не оплатил. Сливаю сюда
     
    1. 555
      0О0, нихуя ник у тебя родной
      12 май 2025 Изменено
  2. Cactuz
    Cactuz 12 май 2025 "Attempt to index nil with..." – моя личная мантра. 7720 5 июл 2019
    прикинь сюда такой зайдет и опа нихуя :ok_lol:
     
    1. 0О0 Автор темы
      Cactuz, Ну и *** бы с ним
  3. Kalipso
    Kalipso 12 май 2025 :love2: TRX&ENERGY(FROM 100₽/66.000) - lzt.lol/2trx :love2: 501 12 апр 2022
    Поэтому всегда нужно брать деньги вперёд, либо гаранта использовать
     
  4. ФРУТС
    ФРУТС 12 май 2025 <3 jenna ortega E> 42 7 фев 2023
    лучше бд вынести в отдельную папку и прописать классами
    красивее, быстрее, удобнее
     
  5. 4b6rat0r_pro
    Токены в коде? Да, мы это любим :da:
     
Top