Files
roa2web-service-auto/backend/modules/telegram/db/database.py
2026-02-24 17:25:00 +00:00

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 {}