fix: 账号页闪烁/浏览类型/截图复制/时区统一
This commit is contained in:
128
database.py
128
database.py
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user