import hashlib import os import sqlite3 import time from threading import Lock import telebot from backend_flask import app from config import DB_PATH # Lock for database operations db_lock = Lock() def init_db(): try: # 1️⃣ Проверяем и создаём каталог, если его нет db_dir = os.path.dirname(DB_PATH) if not os.path.exists(db_dir): os.makedirs(db_dir, exist_ok=True) # Создаём каталог рекурсивно # 2️⃣ Проверяем, существует ли файл базы данных db_exists = os.path.exists(DB_PATH) # 3️⃣ Открываем соединение, если файла нет, он создастся автоматически with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() # 4️⃣ Если базы не было, создаём таблицы if not db_exists: cursor.execute('''CREATE TABLE events ( id INTEGER PRIMARY KEY AUTOINCREMENT, hash TEXT UNIQUE, data TEXT, delivered BOOLEAN)''') cursor.execute('''CREATE TABLE subscriptions ( chat_id INTEGER, region_id TEXT, username TEXT, active BOOLEAN DEFAULT TRUE, skip BOOLEAN DEFAULT FALSE, disaster_only BOOLEAN DEFAULT FALSE, UNIQUE(chat_id, region_id))''') cursor.execute('''CREATE TABLE whitelist ( chat_id INTEGER PRIMARY KEY, username TEXT, user_email TEXT)''') cursor.execute('''CREATE TABLE admins ( chat_id INTEGER PRIMARY KEY, username TEXT)''') cursor.execute('''CREATE TABLE regions ( region_id TEXT PRIMARY KEY, region_name TEXT, active BOOLEAN DEFAULT TRUE)''') cursor.execute('''CREATE TABLE user_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, chat_id INTEGER, username TEXT, action TEXT, timestamp TEXT)''') # Добавляем тестовые данные (если их нет) cursor.execute('''INSERT OR IGNORE INTO regions (region_id, region_name) VALUES ('01', 'Адыгея'), ('02', 'Башкортостан (Уфа)'), ('04', 'Алтай'), ('19', 'Республика Хакасия')''') conn.commit() app.logger.info("✅ Database created and initialized successfully.") else: app.logger.info("✅ Database already exists. Skipping initialization.") except Exception as e: app.logger.error(f"❌ Error initializing database: {e}") finally: if 'conn' in locals(): # Проверяем, была ли создана переменная conn conn.close() def hash_data(data): return hashlib.sha256(str(data).encode('utf-8')).hexdigest() def is_whitelisted(chat_id): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() query = 'SELECT COUNT(*) FROM whitelist WHERE chat_id = ?' telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}") cursor.execute(query, (chat_id,)) count = cursor.fetchone()[0] conn.close() return count > 0 def add_to_whitelist(chat_id, username): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() query = 'INSERT OR IGNORE INTO whitelist (chat_id, username) VALUES (?, ?)' telebot.logger.info(f"Executing query: {query} with chat_id={chat_id}, username={username}") try: cursor.execute(query, (chat_id, username)) conn.commit() except Exception as e: telebot.logger.error(f"Error during add to whitelist: {e}") finally: conn.close() def rundeck_add_to_whitelist(chat_id, username, user_email): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() # Проверка существования chat_id check_query = 'SELECT COUNT(*) FROM whitelist WHERE chat_id = ?' cursor.execute(check_query, (chat_id,)) count = cursor.fetchone()[0] if count > 0: conn.close() return False # Пользователь уже существует # Вставка нового пользователя insert_query = 'INSERT INTO whitelist (chat_id, username, user_email) VALUES (?, ?, ?)' telebot.logger.info( f"Rundeck executing query: {insert_query} with chat_id={chat_id}, username={username}, email={user_email}") cursor.execute(insert_query, (chat_id, username, user_email)) conn.commit() conn.close() return True # Успешное добавление def remove_from_whitelist(chat_id): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() query = 'DELETE FROM whitelist WHERE chat_id = ?' telebot.logger.info(f"Executing query: {query} with chat_id={chat_id}") cursor.execute(query, (chat_id,)) conn.commit() conn.close() def get_admins(): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute('SELECT chat_id FROM admins') admins = cursor.fetchall() admins = [i[0] for i in admins] conn.close() return admins def get_sorted_regions(): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute('SELECT region_id, region_name FROM regions WHERE active = TRUE') regions = cursor.fetchall() conn.close() # Сортируем регионы по числовому значению region_id regions.sort(key=lambda x: int(x[0])) return regions def region_exists(region_id): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute('SELECT COUNT(*) FROM regions WHERE region_id = ? AND active = TRUE', (region_id,)) count = cursor.fetchone()[0] conn.close() return count > 0 def get_user_subscribed_regions(chat_id): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute(''' SELECT regions.region_id, regions.region_name FROM subscriptions JOIN regions ON subscriptions.region_id = regions.region_id WHERE subscriptions.chat_id = ? AND subscriptions.active = TRUE AND subscriptions.skip = FALSE ORDER BY regions.region_id ''', (chat_id,)) regions = cursor.fetchall() conn.close() # Сортируем регионы по числовому значению region_id regions.sort(key=lambda x: int(x[0])) return regions def is_subscribed(chat_id, region_id): with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute(''' SELECT COUNT(*) FROM subscriptions WHERE chat_id = ? AND region_id = ? AND active = TRUE AND skip = FALSE ''', (chat_id, region_id)) count = cursor.fetchone()[0] conn.close() return count > 0 def format_regions_list(regions): return '\n'.join([f"{region_id} - {region_name}" for region_id, region_name in regions]) def log_user_event(chat_id, username, action): timestamp = time.strftime('%Y-%m-%d %H:%M:%S') try: with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() query = 'INSERT INTO user_events (chat_id, username, action, timestamp) VALUES (?, ?, ?, ?)' telebot.logger.debug( f"Executing query: {query} with chat_id={chat_id}, username={username}, action={action}, timestamp={timestamp}") cursor.execute(query, (chat_id, username, action, timestamp)) conn.commit() telebot.logger.info(f"User event logged: {chat_id} ({username}) - {action} at {timestamp}.") except Exception as e: telebot.logger.error(f"Error logging user event: {e}") finally: conn.close()