181 lines
5.0 KiB
Python
181 lines
5.0 KiB
Python
"""
|
|
SQLite Database Setup for Telegram Bot
|
|
|
|
Delegates to shared/database/app_db.py for unified database.
|
|
All tables (telegram, trusted devices, backup codes) live in app.db.
|
|
"""
|
|
|
|
import aiosqlite
|
|
import logging
|
|
from datetime import datetime, timedelta
|
|
|
|
from shared.database.app_db import DB_PATH, get_db as _get_app_db, init_app_db
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Re-export DB_PATH for backward compatibility (operations.py imports it)
|
|
__all__ = [
|
|
'get_db_connection',
|
|
'init_database',
|
|
'cleanup_expired_codes',
|
|
'cleanup_expired_sessions',
|
|
'cleanup_expired_email_codes',
|
|
'get_database_stats',
|
|
'DB_PATH',
|
|
]
|
|
|
|
|
|
async def get_db_connection() -> aiosqlite.Connection:
|
|
"""
|
|
Get a database connection. Delegates to shared app_db.
|
|
|
|
Returns:
|
|
aiosqlite.Connection: Database connection
|
|
"""
|
|
return await _get_app_db()
|
|
|
|
|
|
async def init_database() -> None:
|
|
"""
|
|
Initialize the database. Delegates to shared init_app_db().
|
|
Safe to call multiple times - only creates tables if they don't exist.
|
|
"""
|
|
await init_app_db()
|
|
logger.info("Database initialized successfully (delegated to app_db)")
|
|
|
|
|
|
async def cleanup_expired_codes() -> int:
|
|
"""
|
|
Delete expired authentication codes from the database.
|
|
|
|
Returns:
|
|
int: Number of expired codes deleted
|
|
"""
|
|
try:
|
|
async with aiosqlite.connect(DB_PATH) as db:
|
|
db.row_factory = aiosqlite.Row
|
|
cursor = await db.execute("""
|
|
DELETE FROM telegram_auth_codes
|
|
WHERE expires_at < ?
|
|
""", (datetime.now(),))
|
|
|
|
await db.commit()
|
|
deleted = cursor.rowcount
|
|
|
|
if deleted > 0:
|
|
logger.info(f"Cleaned up {deleted} expired auth codes")
|
|
|
|
return deleted
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to cleanup expired codes: {e}")
|
|
return 0
|
|
|
|
|
|
async def cleanup_expired_sessions() -> int:
|
|
"""
|
|
Delete expired sessions from the database.
|
|
|
|
Returns:
|
|
int: Number of expired sessions deleted
|
|
"""
|
|
try:
|
|
async with aiosqlite.connect(DB_PATH) as db:
|
|
db.row_factory = aiosqlite.Row
|
|
cursor = await db.execute("""
|
|
DELETE FROM telegram_sessions
|
|
WHERE expires_at < ?
|
|
""", (datetime.now(),))
|
|
|
|
await db.commit()
|
|
deleted = cursor.rowcount
|
|
|
|
if deleted > 0:
|
|
logger.info(f"Cleaned up {deleted} expired sessions")
|
|
|
|
return deleted
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to cleanup expired sessions: {e}")
|
|
return 0
|
|
|
|
|
|
async def cleanup_expired_email_codes() -> int:
|
|
"""
|
|
Delete expired and old used email codes from the database.
|
|
|
|
Returns:
|
|
int: Number of email codes deleted
|
|
"""
|
|
try:
|
|
async with aiosqlite.connect(DB_PATH) as db:
|
|
db.row_factory = aiosqlite.Row
|
|
cursor = await db.execute("""
|
|
DELETE FROM email_auth_codes
|
|
WHERE expires_at < ?
|
|
OR (used = 1 AND used_at < ?)
|
|
""", (
|
|
datetime.now(),
|
|
datetime.now() - timedelta(days=1)
|
|
))
|
|
|
|
await db.commit()
|
|
deleted = cursor.rowcount
|
|
|
|
if deleted > 0:
|
|
logger.info(f"Cleaned up {deleted} expired/old email auth codes")
|
|
|
|
return deleted
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to cleanup email codes: {e}")
|
|
return 0
|
|
|
|
|
|
async def get_database_stats() -> dict:
|
|
"""
|
|
Get database statistics for monitoring.
|
|
|
|
Returns:
|
|
dict: Database statistics
|
|
"""
|
|
try:
|
|
async with aiosqlite.connect(DB_PATH) as db:
|
|
db.row_factory = aiosqlite.Row
|
|
stats = {}
|
|
|
|
# Count users
|
|
cursor = await db.execute("SELECT COUNT(*) FROM telegram_users")
|
|
stats['total_users'] = (await cursor.fetchone())[0]
|
|
|
|
cursor = await db.execute(
|
|
"SELECT COUNT(*) FROM telegram_users WHERE is_active = 1"
|
|
)
|
|
stats['active_users'] = (await cursor.fetchone())[0]
|
|
|
|
# Count pending codes
|
|
cursor = await db.execute("""
|
|
SELECT COUNT(*) FROM telegram_auth_codes
|
|
WHERE used = 0 AND expires_at > ?
|
|
""", (datetime.now(),))
|
|
stats['pending_codes'] = (await cursor.fetchone())[0]
|
|
|
|
# Count active sessions
|
|
cursor = await db.execute("""
|
|
SELECT COUNT(*) FROM telegram_sessions
|
|
WHERE expires_at > ?
|
|
""", (datetime.now(),))
|
|
stats['active_sessions'] = (await cursor.fetchone())[0]
|
|
|
|
# Database file size
|
|
if DB_PATH.exists():
|
|
stats['db_size_mb'] = DB_PATH.stat().st_size / (1024 * 1024)
|
|
else:
|
|
stats['db_size_mb'] = 0
|
|
|
|
return stats
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to get database stats: {e}")
|
|
return {}
|