refactor: optimize structure, stability and runtime performance
This commit is contained in:
541
db/migrations.py
541
db/migrations.py
@@ -28,105 +28,136 @@ def set_current_version(conn, version: int) -> None:
|
||||
conn.commit()
|
||||
|
||||
|
||||
def _table_exists(cursor, table_name: str) -> bool:
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (str(table_name),))
|
||||
return cursor.fetchone() is not None
|
||||
|
||||
|
||||
def _get_table_columns(cursor, table_name: str) -> set[str]:
|
||||
cursor.execute(f"PRAGMA table_info({table_name})")
|
||||
return {col[1] for col in cursor.fetchall()}
|
||||
|
||||
|
||||
def _add_column_if_missing(cursor, table_name: str, columns: set[str], column_name: str, column_ddl: str, *, ok_message: str) -> bool:
|
||||
if column_name in columns:
|
||||
return False
|
||||
cursor.execute(f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_ddl}")
|
||||
columns.add(column_name)
|
||||
print(ok_message)
|
||||
return True
|
||||
|
||||
|
||||
def _read_row_value(row, key: str, index: int):
|
||||
if isinstance(row, sqlite3.Row):
|
||||
return row[key]
|
||||
return row[index]
|
||||
|
||||
|
||||
def _get_migration_steps():
|
||||
return [
|
||||
(1, _migrate_to_v1),
|
||||
(2, _migrate_to_v2),
|
||||
(3, _migrate_to_v3),
|
||||
(4, _migrate_to_v4),
|
||||
(5, _migrate_to_v5),
|
||||
(6, _migrate_to_v6),
|
||||
(7, _migrate_to_v7),
|
||||
(8, _migrate_to_v8),
|
||||
(9, _migrate_to_v9),
|
||||
(10, _migrate_to_v10),
|
||||
(11, _migrate_to_v11),
|
||||
(12, _migrate_to_v12),
|
||||
(13, _migrate_to_v13),
|
||||
(14, _migrate_to_v14),
|
||||
(15, _migrate_to_v15),
|
||||
(16, _migrate_to_v16),
|
||||
(17, _migrate_to_v17),
|
||||
(18, _migrate_to_v18),
|
||||
]
|
||||
|
||||
|
||||
def migrate_database(conn, target_version: int) -> None:
|
||||
"""数据库迁移:按版本增量升级(向前兼容)。"""
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("INSERT OR IGNORE INTO db_version (id, version, updated_at) VALUES (1, 0, ?)", (get_cst_now_str(),))
|
||||
conn.commit()
|
||||
|
||||
target_version = int(target_version)
|
||||
current_version = get_current_version(conn)
|
||||
|
||||
if current_version < 1:
|
||||
_migrate_to_v1(conn)
|
||||
current_version = 1
|
||||
if current_version < 2:
|
||||
_migrate_to_v2(conn)
|
||||
current_version = 2
|
||||
if current_version < 3:
|
||||
_migrate_to_v3(conn)
|
||||
current_version = 3
|
||||
if current_version < 4:
|
||||
_migrate_to_v4(conn)
|
||||
current_version = 4
|
||||
if current_version < 5:
|
||||
_migrate_to_v5(conn)
|
||||
current_version = 5
|
||||
if current_version < 6:
|
||||
_migrate_to_v6(conn)
|
||||
current_version = 6
|
||||
if current_version < 7:
|
||||
_migrate_to_v7(conn)
|
||||
current_version = 7
|
||||
if current_version < 8:
|
||||
_migrate_to_v8(conn)
|
||||
current_version = 8
|
||||
if current_version < 9:
|
||||
_migrate_to_v9(conn)
|
||||
current_version = 9
|
||||
if current_version < 10:
|
||||
_migrate_to_v10(conn)
|
||||
current_version = 10
|
||||
if current_version < 11:
|
||||
_migrate_to_v11(conn)
|
||||
current_version = 11
|
||||
if current_version < 12:
|
||||
_migrate_to_v12(conn)
|
||||
current_version = 12
|
||||
if current_version < 13:
|
||||
_migrate_to_v13(conn)
|
||||
current_version = 13
|
||||
if current_version < 14:
|
||||
_migrate_to_v14(conn)
|
||||
current_version = 14
|
||||
if current_version < 15:
|
||||
_migrate_to_v15(conn)
|
||||
current_version = 15
|
||||
if current_version < 16:
|
||||
_migrate_to_v16(conn)
|
||||
current_version = 16
|
||||
if current_version < 17:
|
||||
_migrate_to_v17(conn)
|
||||
current_version = 17
|
||||
if current_version < 18:
|
||||
_migrate_to_v18(conn)
|
||||
current_version = 18
|
||||
for version, migrate_fn in _get_migration_steps():
|
||||
if version > target_version or current_version >= version:
|
||||
continue
|
||||
migrate_fn(conn)
|
||||
current_version = version
|
||||
|
||||
if current_version != int(target_version):
|
||||
set_current_version(conn, int(target_version))
|
||||
if current_version != target_version:
|
||||
set_current_version(conn, target_version)
|
||||
|
||||
|
||||
def _migrate_to_v1(conn):
|
||||
"""迁移到版本1 - 添加缺失字段"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("PRAGMA table_info(system_config)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
system_columns = _get_table_columns(cursor, "system_config")
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
system_columns,
|
||||
"schedule_weekdays",
|
||||
'TEXT DEFAULT "1,2,3,4,5,6,7"',
|
||||
ok_message=" [OK] 添加 schedule_weekdays 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
system_columns,
|
||||
"max_screenshot_concurrent",
|
||||
"INTEGER DEFAULT 3",
|
||||
ok_message=" [OK] 添加 max_screenshot_concurrent 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
system_columns,
|
||||
"max_concurrent_per_account",
|
||||
"INTEGER DEFAULT 1",
|
||||
ok_message=" [OK] 添加 max_concurrent_per_account 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
system_columns,
|
||||
"auto_approve_enabled",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 auto_approve_enabled 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
system_columns,
|
||||
"auto_approve_hourly_limit",
|
||||
"INTEGER DEFAULT 10",
|
||||
ok_message=" [OK] 添加 auto_approve_hourly_limit 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
system_columns,
|
||||
"auto_approve_vip_days",
|
||||
"INTEGER DEFAULT 7",
|
||||
ok_message=" [OK] 添加 auto_approve_vip_days 字段",
|
||||
)
|
||||
|
||||
if "schedule_weekdays" not in columns:
|
||||
cursor.execute('ALTER TABLE system_config ADD COLUMN schedule_weekdays TEXT DEFAULT "1,2,3,4,5,6,7"')
|
||||
print(" [OK] 添加 schedule_weekdays 字段")
|
||||
|
||||
if "max_screenshot_concurrent" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN max_screenshot_concurrent INTEGER DEFAULT 3")
|
||||
print(" [OK] 添加 max_screenshot_concurrent 字段")
|
||||
if "max_concurrent_per_account" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN max_concurrent_per_account INTEGER DEFAULT 1")
|
||||
print(" [OK] 添加 max_concurrent_per_account 字段")
|
||||
if "auto_approve_enabled" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN auto_approve_enabled INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 auto_approve_enabled 字段")
|
||||
if "auto_approve_hourly_limit" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN auto_approve_hourly_limit INTEGER DEFAULT 10")
|
||||
print(" [OK] 添加 auto_approve_hourly_limit 字段")
|
||||
if "auto_approve_vip_days" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN auto_approve_vip_days INTEGER DEFAULT 7")
|
||||
print(" [OK] 添加 auto_approve_vip_days 字段")
|
||||
|
||||
cursor.execute("PRAGMA table_info(task_logs)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
if "duration" not in columns:
|
||||
cursor.execute("ALTER TABLE task_logs ADD COLUMN duration INTEGER")
|
||||
print(" [OK] 添加 duration 字段到 task_logs")
|
||||
task_log_columns = _get_table_columns(cursor, "task_logs")
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"task_logs",
|
||||
task_log_columns,
|
||||
"duration",
|
||||
"INTEGER",
|
||||
ok_message=" [OK] 添加 duration 字段到 task_logs",
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
|
||||
@@ -135,24 +166,39 @@ def _migrate_to_v2(conn):
|
||||
"""迁移到版本2 - 添加代理配置字段"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("PRAGMA table_info(system_config)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
|
||||
if "proxy_enabled" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN proxy_enabled INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 proxy_enabled 字段")
|
||||
|
||||
if "proxy_api_url" not in columns:
|
||||
cursor.execute('ALTER TABLE system_config ADD COLUMN proxy_api_url TEXT DEFAULT ""')
|
||||
print(" [OK] 添加 proxy_api_url 字段")
|
||||
|
||||
if "proxy_expire_minutes" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN proxy_expire_minutes INTEGER DEFAULT 3")
|
||||
print(" [OK] 添加 proxy_expire_minutes 字段")
|
||||
|
||||
if "enable_screenshot" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN enable_screenshot INTEGER DEFAULT 1")
|
||||
print(" [OK] 添加 enable_screenshot 字段")
|
||||
columns = _get_table_columns(cursor, "system_config")
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
columns,
|
||||
"proxy_enabled",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 proxy_enabled 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
columns,
|
||||
"proxy_api_url",
|
||||
'TEXT DEFAULT ""',
|
||||
ok_message=" [OK] 添加 proxy_api_url 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
columns,
|
||||
"proxy_expire_minutes",
|
||||
"INTEGER DEFAULT 3",
|
||||
ok_message=" [OK] 添加 proxy_expire_minutes 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
columns,
|
||||
"enable_screenshot",
|
||||
"INTEGER DEFAULT 1",
|
||||
ok_message=" [OK] 添加 enable_screenshot 字段",
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
|
||||
@@ -161,20 +207,31 @@ def _migrate_to_v3(conn):
|
||||
"""迁移到版本3 - 添加账号状态和登录失败计数字段"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("PRAGMA table_info(accounts)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
|
||||
if "status" not in columns:
|
||||
cursor.execute('ALTER TABLE accounts ADD COLUMN status TEXT DEFAULT "active"')
|
||||
print(" [OK] 添加 accounts.status 字段 (账号状态)")
|
||||
|
||||
if "login_fail_count" not in columns:
|
||||
cursor.execute("ALTER TABLE accounts ADD COLUMN login_fail_count INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 accounts.login_fail_count 字段 (登录失败计数)")
|
||||
|
||||
if "last_login_error" not in columns:
|
||||
cursor.execute("ALTER TABLE accounts ADD COLUMN last_login_error TEXT")
|
||||
print(" [OK] 添加 accounts.last_login_error 字段 (最后登录错误)")
|
||||
columns = _get_table_columns(cursor, "accounts")
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"accounts",
|
||||
columns,
|
||||
"status",
|
||||
'TEXT DEFAULT "active"',
|
||||
ok_message=" [OK] 添加 accounts.status 字段 (账号状态)",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"accounts",
|
||||
columns,
|
||||
"login_fail_count",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 accounts.login_fail_count 字段 (登录失败计数)",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"accounts",
|
||||
columns,
|
||||
"last_login_error",
|
||||
"TEXT",
|
||||
ok_message=" [OK] 添加 accounts.last_login_error 字段 (最后登录错误)",
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
|
||||
@@ -183,12 +240,15 @@ def _migrate_to_v4(conn):
|
||||
"""迁移到版本4 - 添加任务来源字段"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("PRAGMA table_info(task_logs)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
|
||||
if "source" not in columns:
|
||||
cursor.execute('ALTER TABLE task_logs ADD COLUMN source TEXT DEFAULT "manual"')
|
||||
print(" [OK] 添加 task_logs.source 字段 (任务来源: manual/scheduled/immediate)")
|
||||
columns = _get_table_columns(cursor, "task_logs")
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"task_logs",
|
||||
columns,
|
||||
"source",
|
||||
'TEXT DEFAULT "manual"',
|
||||
ok_message=" [OK] 添加 task_logs.source 字段 (任务来源: manual/scheduled/immediate)",
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
|
||||
@@ -300,20 +360,17 @@ def _migrate_to_v6(conn):
|
||||
def _migrate_to_v7(conn):
|
||||
"""迁移到版本7 - 统一存储北京时间(将历史UTC时间字段整体+8小时)"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
def table_exists(table_name: str) -> bool:
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
|
||||
return cursor.fetchone() is not None
|
||||
|
||||
def column_exists(table_name: str, column_name: str) -> bool:
|
||||
cursor.execute(f"PRAGMA table_info({table_name})")
|
||||
return any(row[1] == column_name for row in cursor.fetchall())
|
||||
columns_cache: dict[str, set[str]] = {}
|
||||
|
||||
def shift_utc_to_cst(table_name: str, column_name: str) -> None:
|
||||
if not table_exists(table_name):
|
||||
if not _table_exists(cursor, table_name):
|
||||
return
|
||||
if not column_exists(table_name, column_name):
|
||||
|
||||
if table_name not in columns_cache:
|
||||
columns_cache[table_name] = _get_table_columns(cursor, table_name)
|
||||
if column_name not in columns_cache[table_name]:
|
||||
return
|
||||
|
||||
cursor.execute(
|
||||
f"""
|
||||
UPDATE {table_name}
|
||||
@@ -329,10 +386,6 @@ def _migrate_to_v7(conn):
|
||||
("accounts", "created_at"),
|
||||
("password_reset_requests", "created_at"),
|
||||
("password_reset_requests", "processed_at"),
|
||||
]:
|
||||
shift_utc_to_cst(table, col)
|
||||
|
||||
for table, col in [
|
||||
("smtp_configs", "created_at"),
|
||||
("smtp_configs", "updated_at"),
|
||||
("smtp_configs", "last_success_at"),
|
||||
@@ -340,10 +393,6 @@ def _migrate_to_v7(conn):
|
||||
("email_tokens", "created_at"),
|
||||
("email_logs", "created_at"),
|
||||
("email_stats", "last_updated"),
|
||||
]:
|
||||
shift_utc_to_cst(table, col)
|
||||
|
||||
for table, col in [
|
||||
("task_checkpoints", "created_at"),
|
||||
("task_checkpoints", "updated_at"),
|
||||
("task_checkpoints", "completed_at"),
|
||||
@@ -359,15 +408,23 @@ def _migrate_to_v8(conn):
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 1) 增量字段:random_delay(旧库可能不存在)
|
||||
cursor.execute("PRAGMA table_info(user_schedules)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
if "random_delay" not in columns:
|
||||
cursor.execute("ALTER TABLE user_schedules ADD COLUMN random_delay INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 user_schedules.random_delay 字段")
|
||||
|
||||
if "next_run_at" not in columns:
|
||||
cursor.execute("ALTER TABLE user_schedules ADD COLUMN next_run_at TIMESTAMP")
|
||||
print(" [OK] 添加 user_schedules.next_run_at 字段")
|
||||
columns = _get_table_columns(cursor, "user_schedules")
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"user_schedules",
|
||||
columns,
|
||||
"random_delay",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 user_schedules.random_delay 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"user_schedules",
|
||||
columns,
|
||||
"next_run_at",
|
||||
"TIMESTAMP",
|
||||
ok_message=" [OK] 添加 user_schedules.next_run_at 字段",
|
||||
)
|
||||
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_user_schedules_next_run ON user_schedules(next_run_at)")
|
||||
conn.commit()
|
||||
@@ -392,12 +449,12 @@ def _migrate_to_v8(conn):
|
||||
fixed = 0
|
||||
for row in rows:
|
||||
try:
|
||||
schedule_id = row["id"] if isinstance(row, sqlite3.Row) else row[0]
|
||||
schedule_time = row["schedule_time"] if isinstance(row, sqlite3.Row) else row[1]
|
||||
weekdays = row["weekdays"] if isinstance(row, sqlite3.Row) else row[2]
|
||||
random_delay = row["random_delay"] if isinstance(row, sqlite3.Row) else row[3]
|
||||
last_run_at = row["last_run_at"] if isinstance(row, sqlite3.Row) else row[4]
|
||||
next_run_at = row["next_run_at"] if isinstance(row, sqlite3.Row) else row[5]
|
||||
schedule_id = _read_row_value(row, "id", 0)
|
||||
schedule_time = _read_row_value(row, "schedule_time", 1)
|
||||
weekdays = _read_row_value(row, "weekdays", 2)
|
||||
random_delay = _read_row_value(row, "random_delay", 3)
|
||||
last_run_at = _read_row_value(row, "last_run_at", 4)
|
||||
next_run_at = _read_row_value(row, "next_run_at", 5)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
@@ -430,27 +487,46 @@ def _migrate_to_v9(conn):
|
||||
"""迁移到版本9 - 邮件设置字段迁移(清理 email_service scattered ALTER TABLE)"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='email_settings'")
|
||||
if not cursor.fetchone():
|
||||
if not _table_exists(cursor, "email_settings"):
|
||||
# 邮件表由 email_service.init_email_tables 创建;此处仅做增量字段迁移
|
||||
return
|
||||
|
||||
cursor.execute("PRAGMA table_info(email_settings)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
columns = _get_table_columns(cursor, "email_settings")
|
||||
|
||||
changed = False
|
||||
if "register_verify_enabled" not in columns:
|
||||
cursor.execute("ALTER TABLE email_settings ADD COLUMN register_verify_enabled INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 email_settings.register_verify_enabled 字段")
|
||||
changed = True
|
||||
if "base_url" not in columns:
|
||||
cursor.execute("ALTER TABLE email_settings ADD COLUMN base_url TEXT DEFAULT ''")
|
||||
print(" [OK] 添加 email_settings.base_url 字段")
|
||||
changed = True
|
||||
if "task_notify_enabled" not in columns:
|
||||
cursor.execute("ALTER TABLE email_settings ADD COLUMN task_notify_enabled INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 email_settings.task_notify_enabled 字段")
|
||||
changed = True
|
||||
changed = (
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"email_settings",
|
||||
columns,
|
||||
"register_verify_enabled",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 email_settings.register_verify_enabled 字段",
|
||||
)
|
||||
or changed
|
||||
)
|
||||
changed = (
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"email_settings",
|
||||
columns,
|
||||
"base_url",
|
||||
"TEXT DEFAULT ''",
|
||||
ok_message=" [OK] 添加 email_settings.base_url 字段",
|
||||
)
|
||||
or changed
|
||||
)
|
||||
changed = (
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"email_settings",
|
||||
columns,
|
||||
"task_notify_enabled",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 email_settings.task_notify_enabled 字段",
|
||||
)
|
||||
or changed
|
||||
)
|
||||
|
||||
if changed:
|
||||
conn.commit()
|
||||
@@ -459,18 +535,31 @@ def _migrate_to_v9(conn):
|
||||
def _migrate_to_v10(conn):
|
||||
"""迁移到版本10 - users 邮箱字段迁移(避免运行时 ALTER TABLE)"""
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("PRAGMA table_info(users)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
columns = _get_table_columns(cursor, "users")
|
||||
|
||||
changed = False
|
||||
if "email_verified" not in columns:
|
||||
cursor.execute("ALTER TABLE users ADD COLUMN email_verified INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 users.email_verified 字段")
|
||||
changed = True
|
||||
if "email_notify_enabled" not in columns:
|
||||
cursor.execute("ALTER TABLE users ADD COLUMN email_notify_enabled INTEGER DEFAULT 1")
|
||||
print(" [OK] 添加 users.email_notify_enabled 字段")
|
||||
changed = True
|
||||
changed = (
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"users",
|
||||
columns,
|
||||
"email_verified",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 users.email_verified 字段",
|
||||
)
|
||||
or changed
|
||||
)
|
||||
changed = (
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"users",
|
||||
columns,
|
||||
"email_notify_enabled",
|
||||
"INTEGER DEFAULT 1",
|
||||
ok_message=" [OK] 添加 users.email_notify_enabled 字段",
|
||||
)
|
||||
or changed
|
||||
)
|
||||
|
||||
if changed:
|
||||
conn.commit()
|
||||
@@ -657,19 +746,24 @@ def _migrate_to_v15(conn):
|
||||
"""迁移到版本15 - 邮件设置:新设备登录提醒全局开关"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='email_settings'")
|
||||
if not cursor.fetchone():
|
||||
if not _table_exists(cursor, "email_settings"):
|
||||
# 邮件表由 email_service.init_email_tables 创建;此处仅做增量字段迁移
|
||||
return
|
||||
|
||||
cursor.execute("PRAGMA table_info(email_settings)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
columns = _get_table_columns(cursor, "email_settings")
|
||||
|
||||
changed = False
|
||||
if "login_alert_enabled" not in columns:
|
||||
cursor.execute("ALTER TABLE email_settings ADD COLUMN login_alert_enabled INTEGER DEFAULT 1")
|
||||
print(" [OK] 添加 email_settings.login_alert_enabled 字段")
|
||||
changed = True
|
||||
changed = (
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"email_settings",
|
||||
columns,
|
||||
"login_alert_enabled",
|
||||
"INTEGER DEFAULT 1",
|
||||
ok_message=" [OK] 添加 email_settings.login_alert_enabled 字段",
|
||||
)
|
||||
or changed
|
||||
)
|
||||
|
||||
try:
|
||||
cursor.execute("UPDATE email_settings SET login_alert_enabled = 1 WHERE login_alert_enabled IS NULL")
|
||||
@@ -686,22 +780,24 @@ def _migrate_to_v15(conn):
|
||||
def _migrate_to_v16(conn):
|
||||
"""迁移到版本16 - 公告支持图片字段"""
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("PRAGMA table_info(announcements)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
columns = _get_table_columns(cursor, "announcements")
|
||||
|
||||
if "image_url" not in columns:
|
||||
cursor.execute("ALTER TABLE announcements ADD COLUMN image_url TEXT")
|
||||
if _add_column_if_missing(
|
||||
cursor,
|
||||
"announcements",
|
||||
columns,
|
||||
"image_url",
|
||||
"TEXT",
|
||||
ok_message=" [OK] 添加 announcements.image_url 字段",
|
||||
):
|
||||
conn.commit()
|
||||
print(" [OK] 添加 announcements.image_url 字段")
|
||||
|
||||
|
||||
def _migrate_to_v17(conn):
|
||||
"""迁移到版本17 - 金山文档上传配置与用户开关"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("PRAGMA table_info(system_config)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
|
||||
system_columns = _get_table_columns(cursor, "system_config")
|
||||
system_fields = [
|
||||
("kdocs_enabled", "INTEGER DEFAULT 0"),
|
||||
("kdocs_doc_url", "TEXT DEFAULT ''"),
|
||||
@@ -714,21 +810,29 @@ def _migrate_to_v17(conn):
|
||||
("kdocs_admin_notify_email", "TEXT DEFAULT ''"),
|
||||
]
|
||||
for field, ddl in system_fields:
|
||||
if field not in columns:
|
||||
cursor.execute(f"ALTER TABLE system_config ADD COLUMN {field} {ddl}")
|
||||
print(f" [OK] 添加 system_config.{field} 字段")
|
||||
|
||||
cursor.execute("PRAGMA table_info(users)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
system_columns,
|
||||
field,
|
||||
ddl,
|
||||
ok_message=f" [OK] 添加 system_config.{field} 字段",
|
||||
)
|
||||
|
||||
user_columns = _get_table_columns(cursor, "users")
|
||||
user_fields = [
|
||||
("kdocs_unit", "TEXT DEFAULT ''"),
|
||||
("kdocs_auto_upload", "INTEGER DEFAULT 0"),
|
||||
]
|
||||
for field, ddl in user_fields:
|
||||
if field not in columns:
|
||||
cursor.execute(f"ALTER TABLE users ADD COLUMN {field} {ddl}")
|
||||
print(f" [OK] 添加 users.{field} 字段")
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"users",
|
||||
user_columns,
|
||||
field,
|
||||
ddl,
|
||||
ok_message=f" [OK] 添加 users.{field} 字段",
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
|
||||
@@ -737,15 +841,22 @@ def _migrate_to_v18(conn):
|
||||
"""迁移到版本18 - 金山文档上传:有效行范围配置"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("PRAGMA table_info(system_config)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
|
||||
if "kdocs_row_start" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN kdocs_row_start INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 system_config.kdocs_row_start 字段")
|
||||
|
||||
if "kdocs_row_end" not in columns:
|
||||
cursor.execute("ALTER TABLE system_config ADD COLUMN kdocs_row_end INTEGER DEFAULT 0")
|
||||
print(" [OK] 添加 system_config.kdocs_row_end 字段")
|
||||
columns = _get_table_columns(cursor, "system_config")
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
columns,
|
||||
"kdocs_row_start",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 system_config.kdocs_row_start 字段",
|
||||
)
|
||||
_add_column_if_missing(
|
||||
cursor,
|
||||
"system_config",
|
||||
columns,
|
||||
"kdocs_row_end",
|
||||
"INTEGER DEFAULT 0",
|
||||
ok_message=" [OK] 添加 system_config.kdocs_row_end 字段",
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
|
||||
Reference in New Issue
Block a user