fix: 账号页闪烁/浏览类型/截图复制/时区统一

This commit is contained in:
2025-12-14 11:30:49 +08:00
parent 2ec88eac3b
commit a9c8aac48f
59 changed files with 685 additions and 339 deletions

View File

@@ -54,7 +54,7 @@ config = get_config()
DB_FILE = config.DB_FILE
# 数据库版本 (用于迁移管理)
DB_VERSION = 6
DB_VERSION = 7
# ==================== 时区处理工具函数 ====================
# Bug fix: 统一时区处理,避免混用导致的问题
@@ -379,9 +379,13 @@ def migrate_database():
_migrate_to_v6(conn)
current_version = 6
if current_version < 7:
_migrate_to_v7(conn)
current_version = 7
# 更新版本号
cursor.execute('UPDATE db_version SET version = ?, updated_at = CURRENT_TIMESTAMP WHERE id = 1',
(DB_VERSION,))
cursor.execute('UPDATE db_version SET version = ?, updated_at = ? WHERE id = 1',
(DB_VERSION, get_cst_now_str()))
conn.commit()
if current_version < DB_VERSION:
@@ -587,6 +591,66 @@ def _migrate_to_v6(conn):
conn.commit()
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())
def shift_utc_to_cst(table_name: str, column_name: str) -> None:
if not table_exists(table_name):
return
if not column_exists(table_name, column_name):
return
cursor.execute(
f"""
UPDATE {table_name}
SET {column_name} = datetime({column_name}, '+8 hours')
WHERE {column_name} IS NOT NULL AND {column_name} != ''
"""
)
# 主库(这些字段历史上主要由 CURRENT_TIMESTAMP 产生为UTC
for table, col in [
("users", "created_at"),
("users", "approved_at"),
("admins", "created_at"),
("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"),
("email_settings", "updated_at"),
("email_tokens", "created_at"),
("email_logs", "created_at"),
("email_stats", "last_updated"),
]:
shift_utc_to_cst(table, col)
# 断点续传(同库,表由 task_checkpoint.py 创建)
for table, col in [
("task_checkpoints", "created_at"),
("task_checkpoints", "updated_at"),
("task_checkpoints", "completed_at"),
]:
shift_utc_to_cst(table, col)
conn.commit()
print(" ✓ 时区迁移历史UTC时间已转换为北京时间")
# ==================== 管理员相关 ====================
def ensure_default_admin():
@@ -612,8 +676,8 @@ def ensure_default_admin():
default_password_hash = hash_password_bcrypt(random_password)
cursor.execute(
'INSERT INTO admins (username, password_hash) VALUES (?, ?)',
('admin', default_password_hash)
'INSERT INTO admins (username, password_hash, created_at) VALUES (?, ?, ?)',
('admin', default_password_hash, get_cst_now_str())
)
conn.commit()
print("=" * 60)
@@ -696,10 +760,11 @@ def set_default_vip_days(days):
"""设置默认VIP天数"""
with db_pool.get_db() as conn:
cursor = conn.cursor()
cst_time = get_cst_now_str()
cursor.execute('''
INSERT OR REPLACE INTO vip_config (id, default_vip_days, updated_at)
VALUES (1, ?, CURRENT_TIMESTAMP)
''', (days,))
VALUES (1, ?, ?)
''', (days, cst_time))
conn.commit()
return True
@@ -823,6 +888,7 @@ def create_user(username, password, email=''):
with db_pool.get_db() as conn:
cursor = conn.cursor()
password_hash = hash_password(password)
cst_time = get_cst_now_str()
# 获取默认VIP天数
default_vip_days = get_vip_config()['default_vip_days']
@@ -836,9 +902,9 @@ def create_user(username, password, email=''):
try:
cursor.execute('''
INSERT INTO users (username, password_hash, email, status, vip_expire_time)
VALUES (?, ?, ?, 'pending', ?)
''', (username, password_hash, email, vip_expire_time))
INSERT INTO users (username, password_hash, email, status, vip_expire_time, created_at)
VALUES (?, ?, ?, 'pending', ?, ?)
''', (username, password_hash, email, vip_expire_time, cst_time))
conn.commit()
return cursor.lastrowid
except sqlite3.IntegrityError:
@@ -978,11 +1044,12 @@ def approve_user(user_id):
"""审核通过用户"""
with db_pool.get_db() as conn:
cursor = conn.cursor()
cst_time = get_cst_now_str()
cursor.execute('''
UPDATE users
SET status = 'approved', approved_at = CURRENT_TIMESTAMP
SET status = 'approved', approved_at = ?
WHERE id = ?
''', (user_id,))
''', (cst_time, user_id))
conn.commit()
return cursor.rowcount > 0
@@ -1011,12 +1078,13 @@ def create_account(user_id, account_id, username, password, remember=True, remar
"""创建账号(密码加密存储)"""
with db_pool.get_db() as conn:
cursor = conn.cursor()
cst_time = get_cst_now_str()
# 安全修复:加密存储第三方账号密码
encrypted_password = encrypt_password(password)
cursor.execute('''
INSERT INTO accounts (id, user_id, username, password, remember, remark)
VALUES (?, ?, ?, ?, ?, ?)
''', (account_id, user_id, username, encrypted_password, 1 if remember else 0, remark))
INSERT INTO accounts (id, user_id, username, password, remember, remark, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
''', (account_id, user_id, username, encrypted_password, 1 if remember else 0, remark, cst_time))
conn.commit()
return cursor.lastrowid
@@ -1171,7 +1239,7 @@ def get_system_stats():
cursor.execute('''
SELECT COUNT(*) as count FROM users
WHERE vip_expire_time IS NOT NULL
AND datetime(vip_expire_time) > datetime('now')
AND datetime(vip_expire_time) > datetime('now', 'localtime')
''')
vip_users = cursor.fetchone()['count']
@@ -1291,7 +1359,8 @@ def update_system_config(max_concurrent=None, schedule_enabled=None, schedule_ti
params.append(auto_approve_vip_days)
if updates:
updates.append('updated_at = CURRENT_TIMESTAMP')
updates.append('updated_at = ?')
params.append(get_cst_now_str())
# Bug fix: 验证所有字段名都在白名单中
for update_clause in updates:
field_name = update_clause.split('=')[0].strip()
@@ -1311,7 +1380,7 @@ def get_hourly_registration_count():
cursor = conn.cursor()
cursor.execute('''
SELECT COUNT(*) FROM users
WHERE created_at >= datetime('now', '-1 hour')
WHERE created_at >= datetime('now', 'localtime', '-1 hour')
''')
return cursor.fetchone()[0]
@@ -1483,7 +1552,7 @@ def delete_old_task_logs(days=30, batch_size=1000):
DELETE FROM task_logs
WHERE rowid IN (
SELECT rowid FROM task_logs
WHERE created_at < datetime('now', '-' || ? || ' days')
WHERE created_at < datetime('now', 'localtime', '-' || ? || ' days')
LIMIT ?
)
''', (days, batch_size))
@@ -1533,12 +1602,13 @@ def create_password_reset_request(user_id, new_password):
with db_pool.get_db() as conn:
cursor = conn.cursor()
password_hash = hash_password_bcrypt(new_password)
cst_time = get_cst_now_str()
try:
cursor.execute('''
INSERT INTO password_reset_requests (user_id, new_password_hash, status)
VALUES (?, ?, 'pending')
''', (user_id, password_hash))
INSERT INTO password_reset_requests (user_id, new_password_hash, status, created_at)
VALUES (?, ?, 'pending', ?)
''', (user_id, password_hash, cst_time))
conn.commit()
return cursor.lastrowid
except Exception as e:
@@ -1565,6 +1635,7 @@ def approve_password_reset(request_id):
"""批准密码重置申请"""
with db_pool.get_db() as conn:
cursor = conn.cursor()
cst_time = get_cst_now_str()
try:
# 获取申请信息
@@ -1588,9 +1659,9 @@ def approve_password_reset(request_id):
# 更新申请状态
cursor.execute('''
UPDATE password_reset_requests
SET status = 'approved', processed_at = CURRENT_TIMESTAMP
SET status = 'approved', processed_at = ?
WHERE id = ?
''', (request_id,))
''', (cst_time, request_id))
conn.commit()
return True
@@ -1603,13 +1674,14 @@ def reject_password_reset(request_id):
"""拒绝密码重置申请"""
with db_pool.get_db() as conn:
cursor = conn.cursor()
cst_time = get_cst_now_str()
try:
cursor.execute('''
UPDATE password_reset_requests
SET status = 'rejected', processed_at = CURRENT_TIMESTAMP
SET status = 'rejected', processed_at = ?
WHERE id = ? AND status = 'pending'
''', (request_id,))
''', (cst_time, request_id))
conn.commit()
return cursor.rowcount > 0
except Exception as e:
@@ -1652,7 +1724,7 @@ def clean_old_operation_logs(days=30):
try:
cursor.execute('''
DELETE FROM operation_logs
WHERE created_at < datetime('now', '-' || ? || ' days')
WHERE created_at < datetime('now', 'localtime', '-' || ? || ' days')
''', (days,))
deleted_count = cursor.rowcount
conn.commit()
@@ -2146,7 +2218,7 @@ def clean_old_schedule_logs(days=30):
cursor = conn.cursor()
cursor.execute('''
DELETE FROM schedule_execution_logs
WHERE execute_time < datetime('now', '-' || ? || ' days')
WHERE execute_time < datetime('now', 'localtime', '-' || ? || ' days')
''', (days,))
conn.commit()
return cursor.rowcount