From 8ee73e6572db27fe1437353fd2d5dea9545c3076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E7=BB=8D=E5=BA=B7?= <3052147989@qq.com> Date: Mon, 9 Mar 2026 13:46:45 +0800 Subject: [PATCH] style: apply latest black formatting for ci --- outlook_web/controllers/accounts.py | 24 +-- outlook_web/controllers/scheduler.py | 24 +-- outlook_web/controllers/system.py | 42 ++--- outlook_web/db.py | 234 +++++++++------------------ outlook_web/repositories/accounts.py | 12 +- outlook_web/repositories/groups.py | 6 +- outlook_web/services/refresh.py | 12 +- outlook_web/services/scheduler.py | 12 +- start.py | 1 + 9 files changed, 123 insertions(+), 244 deletions(-) diff --git a/outlook_web/controllers/accounts.py b/outlook_web/controllers/accounts.py index de4ecde..c6bc6b2 100644 --- a/outlook_web/controllers/accounts.py +++ b/outlook_web/controllers/accounts.py @@ -1803,8 +1803,7 @@ def api_get_failed_refresh_logs() -> Any: db = get_db() # 获取每个账号最近一次失败的刷新记录 - cursor = db.execute( - """ + cursor = db.execute(""" SELECT l.*, a.email as account_email, a.status as account_status FROM account_refresh_logs l INNER JOIN ( @@ -1815,8 +1814,7 @@ def api_get_failed_refresh_logs() -> Any: LEFT JOIN accounts a ON l.account_id = a.id WHERE l.status = 'failed' ORDER BY l.created_at DESC - """ - ) + """) logs = [] for row in cursor.fetchall(): @@ -1841,27 +1839,22 @@ def api_get_refresh_stats() -> Any: """获取刷新统计信息(统计当前失败状态的邮箱数量)""" db = get_db() - cursor = db.execute( - """ + cursor = db.execute(""" SELECT MAX(created_at) as last_refresh_time FROM account_refresh_logs WHERE refresh_type IN ('manual', 'manual_all', 'scheduled', 'retry') - """ - ) + """) row = cursor.fetchone() last_refresh_time = row["last_refresh_time"] if row else None - cursor = db.execute( - """ + cursor = db.execute(""" SELECT COUNT(*) as total_accounts FROM accounts WHERE status = 'active' - """ - ) + """) total_accounts = cursor.fetchone()["total_accounts"] - cursor = db.execute( - """ + cursor = db.execute(""" SELECT COUNT(DISTINCT l.account_id) as failed_count FROM account_refresh_logs l INNER JOIN ( @@ -1871,8 +1864,7 @@ def api_get_refresh_stats() -> Any: ) latest ON l.account_id = latest.account_id AND l.created_at = latest.last_refresh INNER JOIN accounts a ON l.account_id = a.id WHERE l.status = 'failed' AND a.status = 'active' - """ - ) + """) failed_count = cursor.fetchone()["failed_count"] return jsonify( diff --git a/outlook_web/controllers/scheduler.py b/outlook_web/controllers/scheduler.py index 9f86181..095b642 100644 --- a/outlook_web/controllers/scheduler.py +++ b/outlook_web/controllers/scheduler.py @@ -35,13 +35,11 @@ def api_get_scheduler_status() -> Any: refresh_cron = settings_repo.get_setting("refresh_cron", "0 2 * * *") # 心跳 - heartbeat_row = conn.execute( - """ + heartbeat_row = conn.execute(""" SELECT value, updated_at FROM settings WHERE key = 'scheduler_heartbeat' - """ - ).fetchone() + """).fetchone() heartbeat = None heartbeat_age_seconds = None @@ -78,28 +76,24 @@ def api_get_scheduler_status() -> Any: lock_info = {"locked": False} # 最近一次定时刷新(含手动触发 scheduled_manual) - last_scheduled_run = conn.execute( - """ + last_scheduled_run = conn.execute(""" SELECT id, trigger_source, status, started_at, finished_at, total, success_count, failed_count, message, trace_id, requested_by_ip FROM refresh_runs WHERE trigger_source IN ('scheduled', 'scheduled_manual') ORDER BY started_at DESC LIMIT 1 - """ - ).fetchone() + """).fetchone() last_scheduled = dict(last_scheduled_run) if last_scheduled_run else None - running_run = conn.execute( - """ + running_run = conn.execute(""" SELECT id, trigger_source, status, started_at, total, success_count, failed_count, trace_id FROM refresh_runs WHERE status = 'running' ORDER BY started_at DESC LIMIT 1 - """ - ).fetchone() + """).fetchone() running = dict(running_run) if running_run else None @@ -119,8 +113,7 @@ def api_get_scheduler_status() -> Any: future_runs = [] else: # 按天数策略:基于最近一次已完成的 scheduled/scheduled_manual 计算 next_due - row = conn.execute( - """ + row = conn.execute(""" SELECT finished_at FROM refresh_runs WHERE trigger_source IN ('scheduled', 'scheduled_manual') @@ -128,8 +121,7 @@ def api_get_scheduler_status() -> Any: AND finished_at IS NOT NULL ORDER BY finished_at DESC LIMIT 1 - """ - ).fetchone() + """).fetchone() last_finished_at = row["finished_at"] if row else None try: last_time = datetime.fromisoformat(last_finished_at) if last_finished_at else None diff --git a/outlook_web/controllers/system.py b/outlook_web/controllers/system.py index fbf8b6d..c3237f6 100644 --- a/outlook_web/controllers/system.py +++ b/outlook_web/controllers/system.py @@ -47,13 +47,11 @@ def api_system_health() -> Any: db_ok = False # Scheduler 心跳 - heartbeat_row = conn.execute( - """ + heartbeat_row = conn.execute(""" SELECT updated_at FROM settings WHERE key = 'scheduler_heartbeat' - """ - ).fetchone() + """).fetchone() heartbeat_age_seconds = None if heartbeat_row and heartbeat_row["updated_at"]: @@ -78,15 +76,13 @@ def api_system_health() -> Any: ).fetchone() locked = bool(lock_row and lock_row["expires_at"] and lock_row["expires_at"] > time.time()) - running_run = conn.execute( - """ + running_run = conn.execute(""" SELECT id, trigger_source, started_at, trace_id FROM refresh_runs WHERE status = 'running' ORDER BY started_at DESC LIMIT 1 - """ - ).fetchone() + """).fetchone() return jsonify( { @@ -137,32 +133,26 @@ def api_system_diagnostics() -> Any: (now_ts,), ).fetchone()["c"] - running_runs = conn.execute( - """ + running_runs = conn.execute(""" SELECT id, trigger_source, started_at, trace_id FROM refresh_runs WHERE status = 'running' ORDER BY started_at DESC LIMIT 5 - """ - ).fetchall() + """).fetchall() - last_runs = conn.execute( - """ + last_runs = conn.execute(""" SELECT id, trigger_source, status, started_at, finished_at, total, success_count, failed_count, trace_id FROM refresh_runs ORDER BY started_at DESC LIMIT 10 - """ - ).fetchall() + """).fetchall() - locks = conn.execute( - """ + locks = conn.execute(""" SELECT name, owner_id, acquired_at, expires_at FROM distributed_locks ORDER BY name ASC - """ - ).fetchall() + """).fetchall() # 数据库升级状态(可验证) schema_version_row = conn.execute( @@ -172,14 +162,12 @@ def api_system_diagnostics() -> Any: last_migration = None try: - mig = conn.execute( - """ + mig = conn.execute(""" SELECT id, from_version, to_version, status, started_at, finished_at, error, trace_id FROM schema_migrations ORDER BY started_at DESC LIMIT 1 - """ - ).fetchone() + """).fetchone() last_migration = dict(mig) if mig else None except Exception: last_migration = None @@ -225,14 +213,12 @@ def api_system_upgrade_status() -> Any: last_migration = None try: - mig = conn.execute( - """ + mig = conn.execute(""" SELECT id, from_version, to_version, status, started_at, finished_at, error, trace_id FROM schema_migrations ORDER BY started_at DESC LIMIT 1 - """ - ).fetchone() + """).fetchone() last_migration = dict(mig) if mig else None except Exception: last_migration = None diff --git a/outlook_web/db.py b/outlook_web/db.py index 77d2024..b090b35 100644 --- a/outlook_web/db.py +++ b/outlook_web/db.py @@ -92,19 +92,16 @@ def init_db(database_path: Optional[str] = None): cursor.execute("BEGIN IMMEDIATE") # 创建设置表 - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) - """ - ) + """) # 数据库迁移记录(用于升级可验证/可诊断) - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS schema_migrations ( id INTEGER PRIMARY KEY AUTOINCREMENT, from_version INTEGER NOT NULL, @@ -115,14 +112,11 @@ def init_db(database_path: Optional[str] = None): error TEXT, trace_id TEXT ) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_schema_migrations_started_at ON schema_migrations(started_at) - """ - ) + """) # 在锁内读取当前 schema 版本(保证一致性) row = cursor.execute("SELECT value FROM settings WHERE key = ?", (DB_SCHEMA_VERSION_KEY,)).fetchone() @@ -155,8 +149,7 @@ def init_db(database_path: Optional[str] = None): # -------------------- Schema 创建/迁移(幂等) -------------------- # 分组表 - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS groups ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, @@ -166,12 +159,10 @@ def init_db(database_path: Optional[str] = None): is_system INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) - """ - ) + """) # 邮箱账号表 - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS accounts ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE NOT NULL, @@ -191,12 +182,10 @@ def init_db(database_path: Optional[str] = None): updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (group_id) REFERENCES groups (id) ) - """ - ) + """) # 临时邮箱表 - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS temp_emails ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE NOT NULL, @@ -204,12 +193,10 @@ def init_db(database_path: Optional[str] = None): created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) - """ - ) + """) # 临时邮件表(存储从 GPTMail 获取的邮件) - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS temp_email_messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, message_id TEXT UNIQUE NOT NULL, @@ -224,12 +211,10 @@ def init_db(database_path: Optional[str] = None): created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (email_address) REFERENCES temp_emails (email) ) - """ - ) + """) # 刷新记录表(账号级) - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS account_refresh_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, account_id INTEGER NOT NULL, @@ -241,18 +226,14 @@ def init_db(database_path: Optional[str] = None): created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (account_id) REFERENCES accounts (id) ON DELETE CASCADE ) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_account_refresh_logs_run_id ON account_refresh_logs(run_id) - """ - ) + """) # 审计日志表 - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS audit_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, action TEXT NOT NULL, @@ -263,36 +244,28 @@ def init_db(database_path: Optional[str] = None): trace_id TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_audit_logs_trace_id ON audit_logs(trace_id) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_audit_logs_created_at ON audit_logs(created_at) - """ - ) + """) # 标签表 - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS tags ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, color TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) - """ - ) + """) # 账号标签关联表 - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS account_tags ( account_id INTEGER NOT NULL, tag_id INTEGER NOT NULL, @@ -301,24 +274,20 @@ def init_db(database_path: Optional[str] = None): FOREIGN KEY (account_id) REFERENCES accounts (id) ON DELETE CASCADE, FOREIGN KEY (tag_id) REFERENCES tags (id) ON DELETE CASCADE ) - """ - ) + """) # 分布式锁(用于刷新冲突控制/多进程一致性) - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS distributed_locks ( name TEXT PRIMARY KEY, owner_id TEXT NOT NULL, acquired_at REAL NOT NULL, expires_at REAL NOT NULL ) - """ - ) + """) # 导出二次验证 Token(持久化,支持重启/多进程) - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS export_verify_tokens ( token TEXT PRIMARY KEY, ip TEXT, @@ -326,24 +295,20 @@ def init_db(database_path: Optional[str] = None): expires_at REAL NOT NULL, created_at REAL NOT NULL ) - """ - ) + """) # 登录速率限制(持久化,支持重启/多进程) - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS login_attempts ( ip TEXT PRIMARY KEY, count INTEGER NOT NULL, last_attempt_at REAL NOT NULL, locked_until_at REAL ) - """ - ) + """) # 刷新运行记录(用于“最近触发/来源/统计/运行中状态”的可验证性) - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS refresh_runs ( id TEXT PRIMARY KEY, trigger_source TEXT NOT NULL, @@ -358,20 +323,15 @@ def init_db(database_path: Optional[str] = None): message TEXT, trace_id TEXT ) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_refresh_runs_started_at ON refresh_runs(started_at) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_refresh_runs_trigger_source ON refresh_runs(trigger_source) - """ - ) + """) # 兼容旧 schema:补齐缺失列 cursor.execute("PRAGMA table_info(accounts)") @@ -420,20 +380,16 @@ def init_db(database_path: Optional[str] = None): cursor.execute("ALTER TABLE audit_logs ADD COLUMN trace_id TEXT") # 默认分组 - cursor.execute( - """ + cursor.execute(""" INSERT OR IGNORE INTO groups (name, description, color) VALUES ('默认分组', '未分组的邮箱', '#666666') - """ - ) + """) # 临时邮箱分组(系统分组) - cursor.execute( - """ + cursor.execute(""" INSERT OR IGNORE INTO groups (name, description, color, is_system) VALUES ('临时邮箱', 'GPTMail 临时邮箱服务', '#00bcf2', 1) - """ - ) + """) # 初始化默认设置:登录密码(自动迁移明文 -> 哈希) cursor.execute("SELECT value FROM settings WHERE key = 'login_password'") @@ -467,98 +423,69 @@ def init_db(database_path: Optional[str] = None): ) # 初始化刷新配置 - cursor.execute( - """ + cursor.execute(""" INSERT OR IGNORE INTO settings (key, value) VALUES ('refresh_interval_days', '30') - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" INSERT OR IGNORE INTO settings (key, value) VALUES ('refresh_delay_seconds', '5') - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" INSERT OR IGNORE INTO settings (key, value) VALUES ('refresh_cron', '0 2 * * *') - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" INSERT OR IGNORE INTO settings (key, value) VALUES ('use_cron_schedule', 'false') - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" INSERT OR IGNORE INTO settings (key, value) VALUES ('enable_scheduled_refresh', 'true') - """ - ) + """) # 初始化轮询配置 - cursor.execute( - """ + cursor.execute(""" INSERT OR IGNORE INTO settings (key, value) VALUES ('enable_auto_polling', 'false') - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" INSERT OR IGNORE INTO settings (key, value) VALUES ('polling_interval', '10') - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" INSERT OR IGNORE INTO settings (key, value) VALUES ('polling_count', '5') - """ - ) + """) # 索引(性能基线) - cursor.execute( - """ + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_accounts_last_refresh_at ON accounts(last_refresh_at) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_accounts_status ON accounts(status) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_accounts_group_id ON accounts(group_id) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_account_refresh_logs_account_id ON account_refresh_logs(account_id) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_account_refresh_logs_account_id_id ON account_refresh_logs(account_id, id) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_account_tags_tag_id ON account_tags(tag_id) - """ - ) + """) # v5: Telegram 推送去重日志(BUG-00011 P2) - cursor.execute( - """ + cursor.execute(""" CREATE TABLE IF NOT EXISTS telegram_push_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, account_id INTEGER NOT NULL, @@ -566,20 +493,15 @@ def init_db(database_path: Optional[str] = None): pushed_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%S', 'now')), UNIQUE(account_id, message_id) ) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_telegram_push_log_account_id ON telegram_push_log(account_id) - """ - ) - cursor.execute( - """ + """) + cursor.execute(""" CREATE INDEX IF NOT EXISTS idx_telegram_push_log_pushed_at ON telegram_push_log(pushed_at) - """ - ) + """) # 迁移现有明文数据为加密数据 migrate_sensitive_data(conn) diff --git a/outlook_web/repositories/accounts.py b/outlook_web/repositories/accounts.py index 09e3f76..91c5eae 100644 --- a/outlook_web/repositories/accounts.py +++ b/outlook_web/repositories/accounts.py @@ -22,14 +22,12 @@ def load_accounts(group_id: int = None) -> List[Dict]: (group_id,), ) else: - cursor = db.execute( - """ + cursor = db.execute(""" SELECT a.*, g.name as group_name, g.color as group_color FROM accounts a LEFT JOIN groups g ON a.group_id = g.id ORDER BY a.created_at DESC - """ - ) + """) rows = cursor.fetchall() tags_by_account: Dict[int, List[Dict[str, Any]]] = {} @@ -417,13 +415,11 @@ def update_telegram_cursor(account_id: int, checked_at: str) -> None: def get_telegram_push_accounts() -> List[Dict]: """返回所有 telegram_push_enabled=1 且非 disabled 状态的账号。""" db = get_db() - rows = db.execute( - """SELECT a.id, a.email, a.provider, a.client_id, a.refresh_token, + rows = db.execute("""SELECT a.id, a.email, a.provider, a.client_id, a.refresh_token, a.imap_host, a.imap_port, a.imap_password, a.telegram_last_checked_at, a.group_id, g.proxy_url FROM accounts a LEFT JOIN groups g ON a.group_id = g.id - WHERE a.telegram_push_enabled = 1 AND a.status != 'disabled'""" - ).fetchall() + WHERE a.telegram_push_enabled = 1 AND a.status != 'disabled'""").fetchall() return [dict(r) for r in rows] diff --git a/outlook_web/repositories/groups.py b/outlook_web/repositories/groups.py index 62dd247..73d9daa 100644 --- a/outlook_web/repositories/groups.py +++ b/outlook_web/repositories/groups.py @@ -9,14 +9,12 @@ from outlook_web.db import get_db def load_groups() -> List[Dict]: """加载所有分组(临时邮箱分组排在最前面)""" db = get_db() - cursor = db.execute( - """ + cursor = db.execute(""" SELECT * FROM groups ORDER BY CASE WHEN name = '临时邮箱' THEN 0 ELSE 1 END, id - """ - ) + """) rows = cursor.fetchall() return [dict(row) for row in rows] diff --git a/outlook_web/services/refresh.py b/outlook_web/services/refresh.py index 82e8ab6..6109aa5 100644 --- a/outlook_web/services/refresh.py +++ b/outlook_web/services/refresh.py @@ -316,8 +316,7 @@ def stream_trigger_scheduled_refresh( ) if (not force) and (not use_cron): - row = conn.execute( - """ + row = conn.execute(""" SELECT finished_at FROM refresh_runs WHERE trigger_source IN ('scheduled', 'scheduled_manual') @@ -325,8 +324,7 @@ def stream_trigger_scheduled_refresh( AND finished_at IS NOT NULL ORDER BY finished_at DESC LIMIT 1 - """ - ).fetchone() + """).fetchone() if row and row["finished_at"]: try: @@ -564,8 +562,7 @@ def refresh_failed_accounts( """重试所有失败的账号(非流式)""" lock_owner_id = uuid.uuid4().hex - cursor = db.execute( - """ + cursor = db.execute(""" SELECT DISTINCT a.id, a.email, a.client_id, a.refresh_token, a.group_id FROM accounts a INNER JOIN ( @@ -575,8 +572,7 @@ def refresh_failed_accounts( ) latest ON a.id = latest.account_id INNER JOIN account_refresh_logs l ON a.id = l.account_id AND l.created_at = latest.last_refresh WHERE l.status = 'failed' AND a.status = 'active' - """ - ) + """) accounts = cursor.fetchall() total = len(accounts) diff --git a/outlook_web/services/scheduler.py b/outlook_web/services/scheduler.py index 7a32752..79fd226 100644 --- a/outlook_web/services/scheduler.py +++ b/outlook_web/services/scheduler.py @@ -233,8 +233,7 @@ def scheduled_refresh_task(app, test_refresh_token): # 按天数策略:未到周期则跳过(不产生账号级刷新日志) if not use_cron: - row = conn.execute( - """ + row = conn.execute(""" SELECT finished_at FROM refresh_runs WHERE trigger_source = 'scheduled' @@ -242,8 +241,7 @@ def scheduled_refresh_task(app, test_refresh_token): AND finished_at IS NOT NULL ORDER BY finished_at DESC LIMIT 1 - """ - ).fetchone() + """).fetchone() if row and row["finished_at"]: try: @@ -278,14 +276,12 @@ def scheduled_refresh_task(app, test_refresh_token): pass # PRD-00005 / TDD-00005:定时刷新只处理 Outlook 账号(IMAP 账号无 OAuth token 刷新语义) - accounts = conn.execute( - """ + accounts = conn.execute(""" SELECT id, email, client_id, refresh_token, group_id FROM accounts WHERE status = 'active' AND (account_type = 'outlook' OR account_type IS NULL) - """ - ).fetchall() + """).fetchall() total = len(accounts) # 更新 run_id 的 total diff --git a/start.py b/start.py index 180229e..da4dca6 100644 --- a/start.py +++ b/start.py @@ -3,6 +3,7 @@ """ 启动脚本 - 智能初始化环境变量并启动 Flask 应用 """ + import os import secrets import shutil