# database.py - ПОЛНЫЙ ИСПРАВЛЕННЫЙ ФАЙЛ С МИГРАЦИЕЙ import sqlite3 import os import json import time import requests from datetime import datetime, timedelta from config import MSK_TZ, GROUP_ID, OWNER_ID # ============================================================ # ТОКЕН ИЗ ПЕРЕМЕННОЙ ОКРУЖЕНИЯ # ============================================================ HF_TOKEN = os.environ.get("HF_TOKEN") if not HF_TOKEN: print("[DB] ❌ НЕТ HF_TOKEN В ПЕРЕМЕННЫХ ОКРУЖЕНИЯ!") print("[DB] Установи: export HF_TOKEN='твой_токен'") raise SystemExit("[DB] НЕТ HF_TOKEN!") REPO_ID = "RomanJordansky/BOT_JORDANS-DATABASE" DB_PATH_IN_REPO = "bot_database.db" HF_URL = f"https://huggingface.co/{REPO_ID}/resolve/main/{DB_PATH_IN_REPO}" DATA_DIR = "bot_data" os.makedirs(DATA_DIR, exist_ok=True) DB_PATH = os.path.join(DATA_DIR, "bot_database.db") print(f"[DB] База данных: {DB_PATH}") # ============================================================ # СОЗДАНИЕ РЕПОЗИТОРИЯ (MODEL) # ============================================================ def create_repo_if_not_exists(): """Создаёт репозиторий с типом MODEL""" try: from huggingface_hub import HfApi, create_repo, repo_exists if repo_exists(repo_id=REPO_ID, token=HF_TOKEN): print(f"[DB] ✅ Репозиторий {REPO_ID} уже существует") return True create_repo( repo_id=REPO_ID, token=HF_TOKEN, repo_type="model", private=False, exist_ok=True ) print(f"[DB] ✅ Репозиторий {REPO_ID} создан как MODEL!") return True except Exception as e: print(f"[DB] ❌ Ошибка создания репозитория: {e}") return False # ============================================================ # ЗАГРУЗКА/СОХРАНЕНИЕ БД # ============================================================ def download_db(): """Скачивает БД с Hugging Face""" print("[DB] Попытка загрузить базу данных...") try: headers = {"User-Agent": "Mozilla/5.0", "Authorization": f"Bearer {HF_TOKEN}"} response = requests.get(HF_URL, headers=headers, timeout=30) if response.status_code == 200: with open(DB_PATH, 'wb') as f: f.write(response.content) print(f"[DB] ✅ База данных загружена! Размер: {os.path.getsize(DB_PATH)} байт") return True else: print(f"[DB] БД не найдена (код {response.status_code})") return False except Exception as e: print(f"[DB] Ошибка загрузки: {e}") return False def upload_db(): """Загружает БД на Hugging Face""" try: from huggingface_hub import HfApi api = HfApi(token=HF_TOKEN) api.upload_file( path_or_fileobj=DB_PATH, path_in_repo=DB_PATH_IN_REPO, repo_id=REPO_ID, repo_type="model", ) print(f"[DB] ✅ БД сохранена на HF! Размер: {os.path.getsize(DB_PATH)} байт") return True except Exception as e: print(f"[DB] ❌ Ошибка сохранения: {e}") return False # ============================================================ # СОЗДАНИЕ РЕПОЗИТОРИЯ И ЗАГРУЗКА БД # ============================================================ create_repo_if_not_exists() db_loaded = download_db() if not db_loaded: print("[DB] БД НЕ НАЙДЕНА! СОЗДАЮ НОВУЮ...") # ============================================================ # ПОДКЛЮЧЕНИЕ К БД # ============================================================ conn = sqlite3.connect(DB_PATH, check_same_thread=False) cursor = conn.cursor() # ============================================================ # ФУНКЦИЯ ДЛЯ ПРОВЕРКИ И ДОБАВЛЕНИЯ КОЛОНОК # ============================================================ def ensure_column_exists(table_name, column_name, column_type): """Проверяет наличие колонки и добавляет её если нет""" try: cursor.execute(f"PRAGMA table_info({table_name})") columns = [col[1] for col in cursor.fetchall()] if column_name not in columns: cursor.execute(f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_type}") print(f"[DB] ✅ Добавлена колонка {column_name} в таблицу {table_name}") return True return False except Exception as e: print(f"[DB] ⚠️ Ошибка при проверке колонки {column_name}: {e}") return False # ============================================================ # СОЗДАНИЕ ТАБЛИЦ (ЕСЛИ ИХ НЕТ) # ============================================================ # 1. Таблица чатов cursor.execute(""" CREATE TABLE IF NOT EXISTS chats ( chat_id INTEGER PRIMARY KEY, peer_id INTEGER, creator_id INTEGER DEFAULT 0, type TEXT DEFAULT 'CH', activated_at TEXT, quiet INTEGER DEFAULT 0 ) """) cursor.execute("PRAGMA table_info(chats)") columns = [col[1] for col in cursor.fetchall()] if 'creator_id' not in columns: cursor.execute("ALTER TABLE chats ADD COLUMN creator_id INTEGER DEFAULT 0") if 'quiet' not in columns: cursor.execute("ALTER TABLE chats ADD COLUMN quiet INTEGER DEFAULT 0") if 'activated_at' not in columns: cursor.execute("ALTER TABLE chats ADD COLUMN activated_at TEXT") # 2. Таблица разрешений (роли) cursor.execute(""" CREATE TABLE IF NOT EXISTS permissions ( user_id INTEGER, chat_id INTEGER, level INTEGER DEFAULT 0, issued_by INTEGER, issued_at TEXT, PRIMARY KEY (user_id, chat_id) ) """) # 3. Таблица глобальных менеджеров cursor.execute(""" CREATE TABLE IF NOT EXISTS global_managers ( user_id INTEGER PRIMARY KEY, level INTEGER, issued_by INTEGER, issued_at TEXT ) """) # 4. Таблица отключенных ролей cursor.execute(""" CREATE TABLE IF NOT EXISTS disabled_roles ( user_id INTEGER PRIMARY KEY, role_level INTEGER, disabled_at TEXT ) """) # 5. Таблица банов cursor.execute(""" CREATE TABLE IF NOT EXISTS bans ( user_id INTEGER, chat_id INTEGER, moder INTEGER, reason TEXT, date TEXT, PRIMARY KEY (user_id, chat_id) ) """) # 6. Таблица глобального бана cursor.execute(""" CREATE TABLE IF NOT EXISTS globalban ( user_id INTEGER PRIMARY KEY, moderator_id INTEGER, reason_gban TEXT, datetime_gban TEXT ) """) # 7. Таблица бана в беседах общения cursor.execute(""" CREATE TABLE IF NOT EXISTS gbanlist ( user_id INTEGER PRIMARY KEY, moderator_id INTEGER, reason_gban TEXT, datetime_gban TEXT ) """) # 8. Таблица черного списка cursor.execute(""" CREATE TABLE IF NOT EXISTS blacklist ( user_id INTEGER PRIMARY KEY, moderator_id INTEGER, reason_gban TEXT, datetime_gban TEXT ) """) # 9. Таблица мутов cursor.execute(""" CREATE TABLE IF NOT EXISTS mutes ( user_id INTEGER, chat_id INTEGER, moderator_id INTEGER, reason TEXT, until_time TEXT, PRIMARY KEY (user_id, chat_id) ) """) # 10. Таблица предупреждений cursor.execute(""" CREATE TABLE IF NOT EXISTS warns ( user_id INTEGER, chat_id INTEGER, moderator_id INTEGER, reason TEXT, date TEXT ) """) # 11. Сводка предупреждений cursor.execute(""" CREATE TABLE IF NOT EXISTS warns_summary ( user_id INTEGER, chat_id INTEGER, count INTEGER DEFAULT 0, PRIMARY KEY (user_id, chat_id) ) """) # 12. Таблица ников cursor.execute(""" CREATE TABLE IF NOT EXISTS nicks ( user_id INTEGER, chat_id INTEGER, nick TEXT, issued_by INTEGER, issued_at TEXT, PRIMARY KEY (user_id, chat_id) ) """) # 13. Глобальные ники cursor.execute(""" CREATE TABLE IF NOT EXISTS global_nicks ( user_id INTEGER PRIMARY KEY, global_nick TEXT, issued_by INTEGER, issued_at TEXT ) """) # 14. Анти-тег - создаем если нет cursor.execute(""" CREATE TABLE IF NOT EXISTS anti_teg ( user_id INTEGER PRIMARY KEY, issued_at TEXT ) """) # ПРОВЕРЯЕМ И ДОБАВЛЯЕМ КОЛОНКУ issued_by (ЕСЛИ ЕЁ НЕТ) ensure_column_exists('anti_teg', 'issued_by', 'INTEGER DEFAULT 0') # 15. Анти-наказание cursor.execute(""" CREATE TABLE IF NOT EXISTS antipunishment ( user_id INTEGER PRIMARY KEY, issued_by INTEGER, issued_at TEXT ) """) # 16. Анти-статс cursor.execute(""" CREATE TABLE IF NOT EXISTS anti_stats ( user_id INTEGER PRIMARY KEY, issued_by INTEGER, issued_at TEXT ) """) # 17. Глобальный статус cursor.execute(""" CREATE TABLE IF NOT EXISTS global_status ( user_id INTEGER PRIMARY KEY, status TEXT, issued_by INTEGER, issued_at TEXT ) """) # 18. Блокировка команд cursor.execute(""" CREATE TABLE IF NOT EXISTS command_ban ( user_id INTEGER PRIMARY KEY, moderator_id INTEGER, reason TEXT, date TEXT ) """) # 19. Отключенные команды cursor.execute(""" CREATE TABLE IF NOT EXISTS disabled_commands ( command TEXT PRIMARY KEY, chat_id INTEGER, disabled_by INTEGER, type TEXT ) """) # 20. Запрещенные слова cursor.execute(""" CREATE TABLE IF NOT EXISTS ban_words ( word TEXT PRIMARY KEY, creator_id INTEGER, time TEXT ) """) # 21. Информация cursor.execute(""" CREATE TABLE IF NOT EXISTS info ( chat_id INTEGER PRIMARY KEY, description TEXT ) """) # 22. Правила cursor.execute(""" CREATE TABLE IF NOT EXISTS rules ( chat_id INTEGER PRIMARY KEY, description TEXT ) """) # 23. Приветствия cursor.execute(""" CREATE TABLE IF NOT EXISTS welcome_texts ( chat_id INTEGER PRIMARY KEY, text TEXT DEFAULT 'Добро пожаловать, %n!', enabled INTEGER DEFAULT 1 ) """) # 24. Забаненные чаты cursor.execute(""" CREATE TABLE IF NOT EXISTS banned_chats ( chat_id INTEGER PRIMARY KEY ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS banschats ( chat_id INTEGER PRIMARY KEY ) """) # 25. Сетки cursor.execute(""" CREATE TABLE IF NOT EXISTS networks ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_by INTEGER, created_at TEXT ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS network_chats ( chat_id INTEGER PRIMARY KEY, network_id INTEGER, FOREIGN KEY (network_id) REFERENCES networks(id) ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS network_permissions ( user_id INTEGER, network_id INTEGER, level INTEGER DEFAULT 0, issued_by INTEGER, issued_at TEXT, PRIMARY KEY (user_id, network_id) ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS network_bans ( user_id INTEGER, network_id INTEGER, moderator_id INTEGER, reason TEXT, date TEXT, PRIMARY KEY (user_id, network_id) ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS network_nicks ( user_id INTEGER, network_id INTEGER, nick TEXT, issued_by INTEGER, issued_at TEXT, PRIMARY KEY (user_id, network_id) ) """) # 26. Активность пользователей cursor.execute(""" CREATE TABLE IF NOT EXISTS user_activity ( user_id INTEGER, chat_id INTEGER, last_activity TEXT, PRIMARY KEY (user_id, chat_id) ) """) # 27. Фото статистики cursor.execute(""" CREATE TABLE IF NOT EXISTS stats_photo_attachment ( user_id INTEGER PRIMARY KEY, photo_number INTEGER ) """) # 28. Отключение логов cursor.execute(""" CREATE TABLE IF NOT EXISTS log_disabled ( user_id INTEGER PRIMARY KEY ) """) # 29. Локальные таблицы cursor.execute(""" CREATE TABLE IF NOT EXISTS local_welcome ( chat_id INTEGER PRIMARY KEY, text TEXT, enabled INTEGER DEFAULT 1 ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS local_mute_expiry ( user_id INTEGER, chat_id INTEGER, expire_at TEXT, PRIMARY KEY (user_id, chat_id) ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS local_warn_expiry ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, chat_id INTEGER, expire_at TEXT ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS local_global_status ( user_id INTEGER PRIMARY KEY, status_text TEXT ) """) # 30. Статистика сообщений cursor.execute(""" CREATE TABLE IF NOT EXISTS message_stats ( user_id INTEGER, chat_id INTEGER, date TEXT, count INTEGER DEFAULT 0, PRIMARY KEY (user_id, chat_id, date) ) """) conn.commit() print("[DB] Все таблицы созданы/проверены") # ============================================================ # ФУНКЦИИ РАБОТЫ С БД # ============================================================ async def check_chat(chat_id: int) -> bool: try: cursor.execute("SELECT chat_id FROM chats WHERE chat_id = ?", (chat_id,)) return cursor.fetchone() is not None except: return False async def new_chat(chat_id: int, peer_id: int, owner_id: int): cursor.execute(""" INSERT OR IGNORE INTO chats (chat_id, peer_id, creator_id, activated_at, type) VALUES (?, ?, ?, ?, 'CH') """, (chat_id, peer_id, owner_id, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def get_chat_type(chat_id: int) -> str: try: cursor.execute("SELECT type FROM chats WHERE chat_id = ?", (chat_id,)) row = cursor.fetchone() return row[0] if row else "CH" except: return "CH" def get_active_notifications(): """Получает активные уведомления""" return [] def deactivate_notification(notif_id): """Деактивирует уведомление""" pass # ============================================================ # РАБОТА С РОЛЯМИ # ============================================================ async def roleG(user_id: int, chat_id: int, level: int): cursor.execute(""" INSERT OR REPLACE INTO permissions (user_id, chat_id, level, issued_by, issued_at) VALUES (?, ?, ?, ?, ?) """, (user_id, chat_id, level, 0, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def globalrole(user_id: int, level: int): cursor.execute(""" INSERT OR REPLACE INTO global_managers (user_id, level, issued_by, issued_at) VALUES (?, ?, ?, ?) """, (user_id, level, 0, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def remove_globalrole(user_id: int): cursor.execute("DELETE FROM global_managers WHERE user_id = ?", (user_id,)) conn.commit() upload_db() # ============================================================ # РАБОТА С БАНАМИ # ============================================================ async def ban(user_id: int, moderator_id: int, chat_id: int, reason: str) -> bool: try: cursor.execute(""" INSERT OR IGNORE INTO bans (user_id, chat_id, moder, reason, date) VALUES (?, ?, ?, ?, ?) """, (user_id, chat_id, moderator_id, reason, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() return True except: return False async def unban(user_id: int, chat_id: int): cursor.execute("DELETE FROM bans WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) conn.commit() upload_db() async def checkban(user_id: int, chat_id: int) -> bool: cursor.execute("SELECT 1 FROM bans WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) return cursor.fetchone() is not None async def banlist(chat_id: int): cursor.execute("SELECT user_id, reason, date FROM bans WHERE chat_id = ?", (chat_id,)) return cursor.fetchall() # ============================================================ # РАБОТА С МУТАМИ (ИСПРАВЛЕНО) # ============================================================ async def add_mute(user_id: int, chat_id: int, moderator_id: int, reason: str, minutes: int): until_time = (datetime.now(MSK_TZ) + timedelta(minutes=minutes)).strftime("%Y-%m-%d %H:%M:%S") cursor.execute(""" INSERT OR REPLACE INTO mutes (user_id, chat_id, moderator_id, reason, until_time) VALUES (?, ?, ?, ?, ?) """, (user_id, chat_id, moderator_id, reason, until_time)) conn.commit() upload_db() async def unmute(user_id: int, chat_id: int): cursor.execute("DELETE FROM mutes WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) conn.commit() upload_db() async def get_mute(user_id: int, chat_id: int): """ Проверяет, находится ли пользователь в муте. ВОЗВРАЩАЕТ: until_time (str) если мут активен, иначе None """ cursor.execute("SELECT until_time FROM mutes WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) row = cursor.fetchone() if row: try: # Преобразуем строку в datetime until_time = datetime.strptime(row[0], "%Y-%m-%d %H:%M:%S") # Делаем until_time aware (с временной зоной), если он naive if until_time.tzinfo is None: until_time = MSK_TZ.localize(until_time) # Получаем текущее время с временной зоной current_time = datetime.now(MSK_TZ) # Сравниваем if until_time > current_time: return row[0] # возвращаем строку с датой окончания мута else: # Мут истек - удаляем await unmute(user_id, chat_id) return None except Exception as e: print(f"[DB] Ошибка в get_mute: {e}") # В случае ошибки считаем, что мута нет return None return None async def mutelist(chat_id: int): cursor.execute(""" SELECT user_id, reason, until_time FROM mutes WHERE chat_id = ? """, (chat_id,)) return cursor.fetchall() # ============================================================ # РАБОТА С ПРЕДУПРЕЖДЕНИЯМИ # ============================================================ async def warn(chat_id: int, user_id: int, moderator_id: int, reason: str) -> int: cursor.execute(""" INSERT INTO warns (user_id, chat_id, moderator_id, reason, date) VALUES (?, ?, ?, ?, ?) """, (user_id, chat_id, moderator_id, reason, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) cursor.execute(""" INSERT OR REPLACE INTO warns_summary (user_id, chat_id, count) VALUES (?, ?, COALESCE((SELECT count FROM warns_summary WHERE user_id = ? AND chat_id = ?), 0) + 1) """, (user_id, chat_id, user_id, chat_id)) conn.commit() upload_db() cursor.execute("SELECT count FROM warns_summary WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) row = cursor.fetchone() return row[0] if row else 0 async def unwarn(chat_id: int, user_id: int): cursor.execute(""" UPDATE warns_summary SET count = count - 1 WHERE user_id = ? AND chat_id = ? AND count > 0 """, (user_id, chat_id)) conn.commit() upload_db() async def get_warns(user_id: int, chat_id: int) -> int: cursor.execute("SELECT count FROM warns_summary WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) row = cursor.fetchone() return row[0] if row else 0 async def warnlist(chat_id: int): cursor.execute(""" SELECT user_id, count FROM warns_summary WHERE chat_id = ? AND count > 0 """, (chat_id,)) return cursor.fetchall() # ============================================================ # РАБОТА С НИКАМИ # ============================================================ async def setnick(user_id: int, chat_id: int, nick: str): cursor.execute(""" INSERT OR REPLACE INTO nicks (user_id, chat_id, nick, issued_by, issued_at) VALUES (?, ?, ?, ?, ?) """, (user_id, chat_id, nick, 0, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def rnick(user_id: int, chat_id: int): cursor.execute("DELETE FROM nicks WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) conn.commit() upload_db() async def get_nick(user_id: int, chat_id: int): cursor.execute("SELECT nick FROM nicks WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) row = cursor.fetchone() return row[0] if row else None async def is_nick(user_id: int, chat_id: int) -> bool: cursor.execute("SELECT 1 FROM nicks WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) return cursor.fetchone() is not None async def nonick(chat_id: int, page: int = 1): offset = (page - 1) * 10 cursor.execute(""" SELECT user_id FROM nicks WHERE chat_id = ? LIMIT 10 OFFSET ? """, (chat_id, offset)) return [row[0] for row in cursor.fetchall()] async def nlist(chat_id: int, page: int = 1): offset = (page - 1) * 10 cursor.execute(""" SELECT user_id, nick, issued_by FROM nicks WHERE chat_id = ? LIMIT 10 OFFSET ? """, (chat_id, offset)) return cursor.fetchall() # ============================================================ # ГЛОБАЛЬНЫЕ НИКИ # ============================================================ async def set_global_nick(user_id: int, nick: str): cursor.execute(""" INSERT OR REPLACE INTO global_nicks (user_id, global_nick, issued_by, issued_at) VALUES (?, ?, ?, ?) """, (user_id, nick, 0, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def remove_global_nick(user_id: int): cursor.execute("DELETE FROM global_nicks WHERE user_id = ?", (user_id,)) conn.commit() upload_db() # ============================================================ # АНТИ-ТЕГ (ИСПРАВЛЕНО!) # ============================================================ async def add_antiteg(user_id: int, issued_by: int = 0): cursor.execute(""" INSERT OR IGNORE INTO anti_teg (user_id, issued_by, issued_at) VALUES (?, ?, ?) """, (user_id, issued_by, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def remove_antiteg(user_id: int): cursor.execute("DELETE FROM anti_teg WHERE user_id = ?", (user_id,)) conn.commit() upload_db() async def check_antiteg(user_id: int) -> bool: cursor.execute("SELECT 1 FROM anti_teg WHERE user_id = ?", (user_id,)) return cursor.fetchone() is not None async def get_antiteg_list(): cursor.execute("SELECT user_id, issued_by FROM anti_teg") return cursor.fetchall() # ============================================================ # АНТИ-НАКАЗАНИЕ # ============================================================ async def add_antipunishment(user_id: int, issued_by: int): cursor.execute(""" INSERT OR IGNORE INTO antipunishment (user_id, issued_by, issued_at) VALUES (?, ?, ?) """, (user_id, issued_by, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def remove_antipunishment(user_id: int): cursor.execute("DELETE FROM antipunishment WHERE user_id = ?", (user_id,)) conn.commit() upload_db() async def check_antipunishment(user_id: int) -> bool: cursor.execute("SELECT 1 FROM antipunishment WHERE user_id = ?", (user_id,)) return cursor.fetchone() is not None # ============================================================ # АНТИ-СТАТС # ============================================================ async def add_anti_stats(user_id: int, issued_by: int): cursor.execute(""" INSERT OR IGNORE INTO anti_stats (user_id, issued_by, issued_at) VALUES (?, ?, ?) """, (user_id, issued_by, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def remove_anti_stats(user_id: int): cursor.execute("DELETE FROM anti_stats WHERE user_id = ?", (user_id,)) conn.commit() upload_db() async def check_anti_stats(user_id: int) -> bool: cursor.execute("SELECT 1 FROM anti_stats WHERE user_id = ?", (user_id,)) return cursor.fetchone() is not None async def get_anti_stats_list(): cursor.execute("SELECT user_id, issued_by FROM anti_stats") return cursor.fetchall() # ============================================================ # БЛОКИРОВКА КОМАНД # ============================================================ async def ban_commands(user_id: int, moderator_id: int): cursor.execute(""" INSERT OR REPLACE INTO command_ban (user_id, moderator_id, reason, date) VALUES (?, ?, ?, ?) """, (user_id, moderator_id, "Заблокированы возможности", datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() async def unban_commands(user_id: int): cursor.execute("DELETE FROM command_ban WHERE user_id = ?", (user_id,)) conn.commit() upload_db() async def is_command_banned(user_id: int) -> bool: cursor.execute("SELECT 1 FROM command_ban WHERE user_id = ?", (user_id,)) return cursor.fetchone() is not None # ============================================================ # ПРИВЕТСТВИЯ # ============================================================ async def get_welcome_text(chat_id: int): cursor.execute("SELECT text, enabled FROM welcome_texts WHERE chat_id = ?", (chat_id,)) row = cursor.fetchone() if row: return row[0], row[1] == 1 return "Добро пожаловать, %n!", False async def set_welcome_text(chat_id: int, text: str): cursor.execute(""" INSERT OR REPLACE INTO welcome_texts (chat_id, text, enabled) VALUES (?, ?, COALESCE((SELECT enabled FROM welcome_texts WHERE chat_id = ?), 1)) """, (chat_id, text, chat_id)) conn.commit() upload_db() async def set_welcome_enabled(chat_id: int, enabled: bool): cursor.execute(""" INSERT OR REPLACE INTO welcome_texts (chat_id, text, enabled) VALUES (?, COALESCE((SELECT text FROM welcome_texts WHERE chat_id = ?), 'Добро пожаловать, %n!'), ?) """, (chat_id, chat_id, 1 if enabled else 0)) conn.commit() upload_db() # ============================================================ # ТИШИНА # ============================================================ async def get_quiet_status(chat_id: int) -> bool: cursor.execute("SELECT quiet FROM chats WHERE chat_id = ?", (chat_id,)) row = cursor.fetchone() return row[0] == 1 if row else False async def quiet(chat_id: int): cursor.execute("UPDATE chats SET quiet = CASE WHEN quiet = 0 THEN 1 ELSE 0 END WHERE chat_id = ?", (chat_id,)) conn.commit() upload_db() # ============================================================ # СТАТИСТИКА СООБЩЕНИЙ # ============================================================ async def get_total_messages(chat_id: int, user_id: int) -> int: try: cursor.execute("SELECT COALESCE(SUM(count), 0) FROM message_stats WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) row = cursor.fetchone() return row[0] if row else 0 except: return 0 async def get_today_messages(chat_id: int, user_id: int) -> int: today_str = datetime.now(MSK_TZ).strftime("%Y-%m-%d") try: cursor.execute("SELECT count FROM message_stats WHERE user_id = ? AND chat_id = ? AND date = ?", (user_id, chat_id, today_str)) row = cursor.fetchone() return row[0] if row else 0 except: return 0 async def add_message_stats(user_id: int, chat_id: int): today_str = datetime.now(MSK_TZ).strftime("%Y-%m-%d") try: cursor.execute(""" INSERT INTO message_stats (user_id, chat_id, date, count) VALUES (?, ?, ?, 1) ON CONFLICT(user_id, chat_id, date) DO UPDATE SET count = count + 1 """, (user_id, chat_id, today_str)) conn.commit() except Exception as e: print(f"[MESSAGE_STATS] Ошибка: {e}") # ============================================================ # СЕТКИ # ============================================================ async def get_network_by_chat(chat_id: int) -> int: cursor.execute("SELECT network_id FROM network_chats WHERE chat_id = ?", (chat_id,)) row = cursor.fetchone() return row[0] if row else None async def get_network_chats(network_id: int) -> list: cursor.execute("SELECT chat_id FROM network_chats WHERE network_id = ?", (network_id,)) return [row[0] for row in cursor.fetchall()] async def add_network(created_by: int) -> int: cursor.execute(""" INSERT INTO networks (created_by, created_at) VALUES (?, ?) """, (created_by, datetime.now(MSK_TZ).strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() upload_db() return cursor.lastrowid async def add_chat_to_network(chat_id: int, network_id: int): cursor.execute("INSERT OR IGNORE INTO network_chats (chat_id, network_id) VALUES (?, ?)", (chat_id, network_id)) conn.commit() upload_db() async def remove_chat_from_network(chat_id: int): cursor.execute("DELETE FROM network_chats WHERE chat_id = ?", (chat_id,)) conn.commit() upload_db() # ============================================================ # БАН БЕСЕД # ============================================================ async def add_banschat_safe(chat_id: int): cursor.execute("INSERT OR IGNORE INTO banschats (chat_id) VALUES (?)", (chat_id,)) conn.commit() upload_db() async def remove_banschat_safe(chat_id: int): cursor.execute("DELETE FROM banschats WHERE chat_id = ?", (chat_id,)) conn.commit() upload_db() async def is_chat_banned_safe(chat_id: int) -> bool: cursor.execute("SELECT 1 FROM banschats WHERE chat_id = ?", (chat_id,)) return cursor.fetchone() is not None async def get_banschats_safe(): cursor.execute("SELECT chat_id FROM banschats") return [row[0] for row in cursor.fetchall()] # ============================================================ # ПОЛУЧЕНИЕ РОЛИ # ============================================================ async def get_effective_role(user_id: int, chat_id: int) -> int: try: cursor.execute("SELECT user_id FROM disabled_roles WHERE user_id = ?", (user_id,)) if cursor.fetchone(): return 0 except: pass if user_id == OWNER_ID: return 12 cursor.execute("SELECT level FROM global_managers WHERE user_id = ?", (user_id,)) global_role = cursor.fetchone() if global_role: return global_role[0] cursor.execute("SELECT level FROM permissions WHERE user_id = ? AND chat_id = ?", (user_id, chat_id)) local_role = cursor.fetchone() if local_role: return local_role[0] return 0 # ============================================================ # СОВМЕСТИМОСТЬ # ============================================================ sql = cursor database = conn print("[DB] Все функции загружены")