From 7657e1b2fa251a2ea372710ad75cb395a3c0e374 Mon Sep 17 00:00:00 2001
From: hyb <kk_huangyangbo@163.com>
Date: Fri, 30 Jan 2026 07:15:55 +0000
Subject: [PATCH] feat: 新增将两种加密方式合并一个脚本、新增批量修改邮箱功能
---
测试组/脚本/Change_password/数据库密码批量修改工具(合并版).py | 191 +++++++++++++++++++++++++++++++++++++++++------
1 files changed, 165 insertions(+), 26 deletions(-)
diff --git "a/\346\265\213\350\257\225\347\273\204/\350\204\232\346\234\254/Change_password/\346\225\260\346\215\256\345\272\223\345\257\206\347\240\201\346\211\271\351\207\217\344\277\256\346\224\271\345\267\245\345\205\267\357\274\210\345\220\210\345\271\266\347\211\210\357\274\211.py" "b/\346\265\213\350\257\225\347\273\204/\350\204\232\346\234\254/Change_password/\346\225\260\346\215\256\345\272\223\345\257\206\347\240\201\346\211\271\351\207\217\344\277\256\346\224\271\345\267\245\345\205\267\357\274\210\345\220\210\345\271\266\347\211\210\357\274\211.py"
index 90f2afa..2d0b0d5 100644
--- "a/\346\265\213\350\257\225\347\273\204/\350\204\232\346\234\254/Change_password/\346\225\260\346\215\256\345\272\223\345\257\206\347\240\201\346\211\271\351\207\217\344\277\256\346\224\271\345\267\245\345\205\267\357\274\210\345\220\210\345\271\266\347\211\210\357\274\211.py"
+++ "b/\346\265\213\350\257\225\347\273\204/\350\204\232\346\234\254/Change_password/\346\225\260\346\215\256\345\272\223\345\257\206\347\240\201\346\211\271\351\207\217\344\277\256\346\224\271\345\267\245\345\205\267\357\274\210\345\220\210\345\271\266\347\211\210\357\274\211.py"
@@ -198,14 +198,15 @@
error_signal = pyqtSignal(str)
export_finished_signal = pyqtSignal(str)
- def __init__(self, excel_path, new_password, mode, hash_mode, user_filter=None, selected_projects=None):
+ def __init__(self, excel_path, new_value, mode, hash_mode, user_filter=None, selected_projects=None, modify_type='password'):
super().__init__()
self.excel_path = excel_path
- self.new_password = new_password
+ self.new_value = new_value # 新密码或新邮箱
self.mode = mode # 'all' 或 'specific'
self.hash_mode = hash_mode # 'bcrypt' 或 'argon2id'
self.user_filter = user_filter
self.selected_projects = selected_projects
+ self.modify_type = modify_type # 'password' 或 'email'
self.updaters = []
self.log_records = []
self.is_running = True
@@ -250,7 +251,7 @@
for _, row in df_filtered.iterrows():
project, host, port, database, user, password = row[:6]
self.log_signal.emit(f"准备处理项目:{project} | 数据库:{database} | 端口:{port}")
- updater = ProjectUpdater(project, host, database, user, password, port, self.hash_mode)
+ updater = ProjectUpdater(project, host, database, user, password, port, self.hash_mode, self.modify_type)
self.updaters.append(updater)
# 执行更新任务
@@ -262,10 +263,16 @@
self.log_signal.emit(f"正在处理项目: {updater.project}")
# 运行更新
- success = updater.update_database(
- user_filter=self.user_filter if self.mode == 'specific' else None,
- new_password=self.new_password
- )
+ if self.modify_type == 'password':
+ success = updater.update_database(
+ user_filter=self.user_filter if self.mode == 'specific' else None,
+ new_password=self.new_value
+ )
+ else:
+ success = updater.update_email(
+ user_filter=self.user_filter if self.mode == 'specific' else None,
+ new_email=self.new_value
+ )
if success:
self.log_records.extend(updater.log_records)
@@ -332,7 +339,7 @@
conn = updater.connect()
if conn:
cursor = conn.cursor()
- success = updater.export_user_info(cursor, self.new_password)
+ success = updater.export_user_info(cursor, self.new_value)
cursor.close()
conn.close()
@@ -350,7 +357,7 @@
class ProjectUpdater:
"""单个项目更新器"""
- def __init__(self, project, host, database, user, password, port=3306, hash_mode='bcrypt'):
+ def __init__(self, project, host, database, user, password, port=3306, hash_mode='bcrypt', modify_type='password'):
self.project = project
self.host = host
self.database = database
@@ -358,6 +365,7 @@
self.db_password = password
self.port = port
self.hash_mode = hash_mode # 'bcrypt' 或 'argon2id'
+ self.modify_type = modify_type # 'password' 或 'email'
self.updated_users = []
self.log_records = []
@@ -448,7 +456,7 @@
except Error:
return "获取失败"
- def export_user_info(self, cursor, new_password):
+ def export_user_info(self, cursor, new_value):
"""导出用户信息到Excel"""
try:
if not self.updated_users:
@@ -469,21 +477,32 @@
# 准备导出数据
export_data = []
for user in self.updated_users:
- export_data.append({
- '用户名': user['login_name'],
- '密码': new_password,
- '姓名': user['name'],
- '角色名称': role_name_map.get(user['role_id'], '无角色')
- })
+ if self.modify_type == 'password':
+ export_data.append({
+ '用户名': user['login_name'],
+ '密码': new_value,
+ '姓名': user['name'],
+ '角色名称': role_name_map.get(user['role_id'], '无角色')
+ })
+ else: # 修改邮箱
+ export_data.append({
+ '用户名': user['login_name'],
+ '邮箱': new_value,
+ '姓名': user['name'],
+ '角色名称': role_name_map.get(user['role_id'], '无角色')
+ })
# 创建DataFrame并导出
df_export = pd.DataFrame(export_data)
- # 按照要求格式化文件名:项目名称测试环境账号密码_年月日
- safe_project_name = re.sub(r'[\\/*?:"<>|]', "", self.project)
+ # 按照要求格式化文件名
+ safe_project_name = re.sub(r'[\/*?:"<>|]', "", self.project)
safe_project_name = safe_project_name.replace(" ", "_")
date_str = datetime.now().strftime("%Y%m%d")
- filename = f"{safe_project_name}测试环境账号密码_{date_str}.xlsx"
+ if self.modify_type == 'password':
+ filename = f"{safe_project_name}测试环境账号密码_{date_str}.xlsx"
+ else: # 修改邮箱
+ filename = f"{safe_project_name}测试环境账号邮箱_{date_str}.xlsx"
filepath = os.path.join(DEFAULT_EXPORT_DIR, filename)
df_export.to_excel(filepath, index=False)
@@ -555,6 +574,72 @@
if conn:
conn.close()
+ def update_email(self, user_filter=None, new_email=''):
+ """更新数据库中的用户邮箱"""
+ conn = None
+ cursor = None
+ try:
+ conn = self.connect()
+ if not conn:
+ return False
+
+ # 使用同步方式创建游标
+ cursor = conn.cursor()
+
+ # 获取需要更新的用户
+ users = self.get_users_to_update(cursor, user_filter)
+
+ if not users:
+ return False
+
+ # 更新每个用户的邮箱
+ for uid, login_name, name, current_role_id in users:
+ success = self.update_user_email(cursor, uid, login_name, new_email)
+
+ if success:
+ # 记录更新成功的用户信息
+ self.updated_users.append({
+ 'id': uid,
+ 'login_name': login_name,
+ 'name': name,
+ 'role_id': current_role_id
+ })
+
+ # 写入日志
+ self.log_records.append({
+ '项目': self.project,
+ '数据库': self.database,
+ '用户ID': uid,
+ '用户名': login_name,
+ '新邮箱': new_email
+ })
+
+ # 提交事务
+ conn.commit()
+ return True
+
+ except Error:
+ return False
+ finally:
+ if cursor:
+ cursor.close()
+ if conn:
+ conn.close()
+
+ def update_user_email(self, cursor, user_id, login_name, new_email):
+ """更新用户邮箱"""
+ try:
+ # 构造更新 SQL
+ update_sql = """
+ UPDATE sys_user
+ SET email = %s
+ WHERE id = %s
+ """
+ cursor.execute(update_sql, (new_email, user_id))
+ return True
+ except Error:
+ return False
+
class PasswordUpdaterApp(QMainWindow):
"""主应用程序窗口"""
@@ -593,6 +678,24 @@
excel_layout.addWidget(excel_browse_btn)
config_layout.addWidget(excel_group)
+ # 修改类型选择
+ modify_type_group = QGroupBox("修改类型")
+ modify_type_layout = QVBoxLayout(modify_type_group)
+
+ self.modify_type_group = QButtonGroup()
+ self.modify_password_radio = QRadioButton("修改密码")
+ self.modify_email_radio = QRadioButton("修改邮箱")
+
+ # 默认选择修改密码
+ self.modify_password_radio.setChecked(True)
+
+ self.modify_type_group.addButton(self.modify_password_radio)
+ self.modify_type_group.addButton(self.modify_email_radio)
+
+ modify_type_layout.addWidget(self.modify_password_radio)
+ modify_type_layout.addWidget(self.modify_email_radio)
+ config_layout.addWidget(modify_type_group)
+
# 新密码设置
password_group = QGroupBox("新密码设置")
password_layout = QHBoxLayout(password_group)
@@ -601,6 +704,16 @@
password_layout.addWidget(QLabel("新密码:"))
password_layout.addWidget(self.password_edit)
config_layout.addWidget(password_group)
+
+ # 新邮箱设置
+ email_group = QGroupBox("新邮箱设置")
+ email_layout = QHBoxLayout(email_group)
+ self.email_edit = QLineEdit()
+ self.email_edit.setPlaceholderText("请输入新邮箱")
+ self.email_edit.setEnabled(False) # 默认禁用
+ email_layout.addWidget(QLabel("新邮箱:"))
+ email_layout.addWidget(self.email_edit)
+ config_layout.addWidget(email_group)
# 加密方式选择
hash_group = QGroupBox("加密方式选择")
@@ -647,6 +760,10 @@
lambda: self.usernames_edit.setEnabled(not self.all_users_radio.isChecked()))
self.specific_users_radio.toggled.connect(
lambda: self.usernames_edit.setEnabled(self.specific_users_radio.isChecked()))
+
+ # 修改类型选择信号
+ self.modify_password_radio.toggled.connect(self.on_modify_type_changed)
+ self.modify_email_radio.toggled.connect(self.on_modify_type_changed)
mode_layout.addWidget(self.all_users_radio)
mode_layout.addWidget(self.specific_users_radio)
@@ -742,20 +859,31 @@
return
user_filter = [name.strip() for name in usernames.replace(',', ',').split(',')]
- # 获取新密码
- new_password = self.password_edit.text()
- if not new_password:
- QMessageBox.warning(self, "错误", "请输入新密码")
- return
+ # 获取修改类型
+ modify_type = 'password' if self.modify_password_radio.isChecked() else 'email'
+
+ # 获取新密码或新邮箱
+ new_value = ''
+ if modify_type == 'password':
+ new_value = self.password_edit.text()
+ if not new_value:
+ QMessageBox.warning(self, "错误", "请输入新密码")
+ return
+ else:
+ new_value = self.email_edit.text()
+ if not new_value:
+ QMessageBox.warning(self, "错误", "请输入新邮箱")
+ return
# 创建并启动更新线程
self.updater_thread = DatabaseUpdater(
self.excel_path_edit.text(),
- new_password,
+ new_value,
mode,
hash_mode,
user_filter,
- selected_projects
+ selected_projects,
+ modify_type
)
# 连接信号
@@ -801,6 +929,17 @@
self.log_text.append(f"开始导出项目 {project_name} 的用户信息...")
self.updater_thread.export_user_info(project_name)
+ def on_modify_type_changed(self):
+ """修改类型变更时的处理"""
+ is_modify_password = self.modify_password_radio.isChecked()
+ # 启用或禁用密码相关控件
+ self.password_edit.setEnabled(is_modify_password)
+ # 启用或禁用邮箱相关控件
+ self.email_edit.setEnabled(not is_modify_password)
+ # 启用或禁用加密方式选择
+ self.bcrypt_radio.setEnabled(is_modify_password)
+ self.argon2id_radio.setEnabled(is_modify_password)
+
def show_error(self, error_msg):
"""显示错误信息"""
QMessageBox.critical(self, "错误", error_msg)
--
Gitblit v1.9.1