import aiosqlite from datetime import datetime import json DB_NAME = "database/database.db" async def init_db(): async with aiosqlite.connect(DB_NAME) as db: # Пользователи await db.execute(""" CREATE TABLE IF NOT EXISTS users( user_id INTEGER PRIMARY KEY, username TEXT, first_name TEXT, last_name TEXT, phone TEXT, email TEXT, group_id INTEGER, group_name TEXT, subgroup TEXT, created_at TEXT, last_seen TEXT ) """) # Кэш расписания await db.execute(""" CREATE TABLE IF NOT EXISTS schedule_cache( id INTEGER PRIMARY KEY AUTOINCREMENT, group_id INTEGER NOT NULL, date TEXT NOT NULL, data TEXT NOT NULL, created_at TEXT NOT NULL, UNIQUE(group_id, date) ) """) # Индекс await db.execute(""" CREATE INDEX IF NOT EXISTS idx_schedule_cache ON schedule_cache(group_id, date) """) # Поддержка await db.execute(""" CREATE TABLE IF NOT EXISTS support( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, message TEXT NOT NULL, answer TEXT, status TEXT DEFAULT 'open', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """) await db.commit() async def save_group( user_id: int, group_id: int, group_name: str, subgroup: str | None = None ): async with aiosqlite.connect(DB_NAME) as db: await db.execute( """ INSERT INTO users( user_id, group_id, group_name, subgroup ) VALUES(?,?,?,?) ON CONFLICT(user_id) DO UPDATE SET group_id = excluded.group_id, group_name = excluded.group_name, subgroup = excluded.subgroup """, ( user_id, group_id, group_name, subgroup ) ) await db.commit() async def get_group( user_id: int ): async with aiosqlite.connect(DB_NAME) as db: cursor = await db.execute( """ SELECT group_id, group_name, subgroup FROM users WHERE user_id=? """, ( user_id, ) ) row = await cursor.fetchone() if row is None: return None return { "group_id": row[0], "group_name": row[1], "subgroup": row[2] } async def delete_group( user_id: int ): async with aiosqlite.connect(DB_NAME) as db: await db.execute( """ DELETE FROM users WHERE user_id=? """, ( user_id, ) ) await db.commit() async def update_subgroup( user_id: int, subgroup: str ): async with aiosqlite.connect(DB_NAME) as db: await db.execute( """ UPDATE users SET subgroup=? WHERE user_id=? """, ( subgroup, user_id ) ) await db.commit() async def create_ticket( user_id: int, message: str ): async with aiosqlite.connect(DB_NAME) as db: cursor = await db.execute( """ INSERT INTO support( user_id, message ) VALUES(?,?) """, ( user_id, message ) ) await db.commit() return cursor.lastrowid #tickets async def get_ticket(ticket_id: int): async with aiosqlite.connect(DB_NAME) as db: cursor = await db.execute( """ SELECT id, user_id, message, status FROM support WHERE id=? """, (ticket_id,) ) row = await cursor.fetchone() return row async def get_tickets(): async with aiosqlite.connect(DB_NAME) as db: cursor = await db.execute( """ SELECT id, user_id, message, status FROM support WHERE status='open' ORDER BY id DESC """ ) rows = await cursor.fetchall() return rows async def close_ticket(ticket_id: int): async with aiosqlite.connect(DB_NAME) as db: await db.execute( """ UPDATE support SET status='closed' WHERE id=? """, (ticket_id,) ) await db.commit() async def update_user( user_id: int, username: str | None = None, first_name: str | None = None, last_name: str | None = None ): now = datetime.now().isoformat() async with aiosqlite.connect(DB_NAME) as db: await db.execute( """ INSERT INTO users( user_id, username, first_name, last_name, created_at, last_seen ) VALUES(?,?,?,?,?,?) ON CONFLICT(user_id) DO UPDATE SET username=excluded.username, first_name=excluded.first_name, last_name=excluded.last_name, last_seen=excluded.last_seen """, ( user_id, username, first_name, last_name, now, now ) ) await db.commit() async def save_phone( user_id: int, phone: str ): async with aiosqlite.connect(DB_NAME) as db: await db.execute( """ UPDATE users SET phone=? WHERE user_id=? """, ( phone, user_id ) ) await db.commit() async def get_cached_schedule( group_id: int, schedule_date: str, ttl_minutes: int ): async with aiosqlite.connect(DB_NAME) as db: cursor = await db.execute( """ SELECT data, created_at FROM schedule_cache WHERE group_id=? AND date=? """, ( group_id, schedule_date ) ) row = await cursor.fetchone() if row is None: return None created = datetime.fromisoformat( row[1] ) age = ( datetime.now() - created ).total_seconds() / 60 # кэш устарел if age > ttl_minutes: return None return json.loads(row[0]) async def save_schedule_cache( group_id: int, schedule_date: str, data: dict ): async with aiosqlite.connect(DB_NAME) as db: await db.execute( """ INSERT INTO schedule_cache( group_id, date, data, created_at ) VALUES(?,?,?,?) ON CONFLICT(group_id, date) DO UPDATE SET data = excluded.data, created_at = excluded.created_at """, ( group_id, schedule_date, json.dumps( data, ensure_ascii=False ), datetime.now().isoformat() ) ) await db.commit() async def clear_old_cache(days: int = 30): async with aiosqlite.connect(DB_NAME) as db: cursor = await db.execute( """ DELETE FROM schedule_cache WHERE datetime(created_at) < datetime('now', ?) """, (f"-{days} days",) ) await db.commit() return cursor.rowcount async def get_active_groups(): async with aiosqlite.connect(DB_NAME) as db: cursor = await db.execute( """ SELECT DISTINCT group_id FROM users WHERE group_id IS NOT NULL """ ) rows = await cursor.fetchall() return [row[0] for row in rows]