Optimize database and deployment: fix SQL injection, async auth, persist data

- Move SQLite DB to data/ directory and track in git for portability
- Fix SQL injection in cleanup_old_emails (use parameterized query)
- Replace sync requests with async httpx in auth.py
- Enable WAL mode and foreign keys for SQLite
- Add UNIQUE constraint and foreign key to account_tags table
- Remove redundant indexes on primary key columns
- Mount data/ volume in docker-compose for persistence
- Remove unused requests dependency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-06 00:57:35 +08:00
parent 5b01caf8e3
commit 889f4f15d5
6 changed files with 37 additions and 30 deletions

View File

@@ -18,9 +18,11 @@ logger = logging.getLogger(__name__)
class DatabaseManager:
"""数据库管理器"""
def __init__(self, db_path: str = "outlook_manager.db"):
def __init__(self, db_path: str = "data/outlook_manager.db"):
self.db_path = db_path
self._local = threading.local()
# 确保数据目录存在
Path(db_path).parent.mkdir(parents=True, exist_ok=True)
self.init_database()
def get_connection(self) -> sqlite3.Connection:
@@ -28,6 +30,9 @@ class DatabaseManager:
if not hasattr(self._local, 'connection'):
self._local.connection = sqlite3.connect(self.db_path)
self._local.connection.row_factory = sqlite3.Row
# 启用WAL模式提升并发读性能
self._local.connection.execute('PRAGMA journal_mode=WAL')
self._local.connection.execute('PRAGMA foreign_keys=ON')
return self._local.connection
def init_database(self):
@@ -51,10 +56,11 @@ class DatabaseManager:
cursor.execute('''
CREATE TABLE IF NOT EXISTS account_tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
tags TEXT NOT NULL, -- JSON格式存储标签数组
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (email) REFERENCES accounts(email) ON DELETE CASCADE
)
''')
@@ -114,9 +120,8 @@ class DatabaseManager:
cursor.execute(f"ALTER TABLE claude_payment_status ADD COLUMN {col} TEXT {default}")
logger.info(f"已为 claude_payment_status 添加 {col}")
# 创建索引
cursor.execute('CREATE INDEX IF NOT EXISTS idx_accounts_email ON accounts(email)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_account_tags_email ON account_tags(email)')
# 创建索引accounts.email 是 PRIMARY KEY无需额外索引
# account_tags.email 已有 UNIQUE 约束,无需额外索引
cursor.execute('CREATE INDEX IF NOT EXISTS idx_email_cache_email ON email_cache(email)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_email_cache_message_id ON email_cache(message_id)')
@@ -309,9 +314,9 @@ class DatabaseManager:
conn = self.get_connection()
cursor = conn.cursor()
cursor.execute('''
DELETE FROM email_cache
WHERE created_at < datetime('now', '-{} days')
'''.format(days))
DELETE FROM email_cache
WHERE created_at < datetime('now', ? || ' days')
''', (f'-{days}',))
deleted_count = cursor.rowcount
conn.commit()
return deleted_count