feat: 添加邮件功能第五阶段 - 用户邮箱绑定
1. 添加邮箱绑定验证邮件模板 (templates/email/bind_email.html) 2. 在email_service.py中添加: - send_bind_email_verification() 发送绑定验证邮件 - verify_bind_email_token() 验证绑定Token 3. 在database.py中添加: - update_user_email() 更新用户邮箱 4. 在app.py中添加API: - GET /api/user/email - 获取用户邮箱信息 - POST /api/user/bind-email - 发送绑定验证邮件 - GET /api/verify-bind-email/<token> - 验证绑定Token - POST /api/user/unbind-email - 解绑邮箱 5. 更新templates/index.html: - 将"修改密码"弹窗改为"个人设置" - 添加邮箱绑定/解绑功能UI - 显示邮箱状态(未绑定/待验证/已验证) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
108
app.py
108
app.py
@@ -2841,6 +2841,114 @@ def change_user_password():
|
||||
return jsonify({"error": "密码更新失败"}), 500
|
||||
|
||||
|
||||
@app.route('/api/user/email', methods=['GET'])
|
||||
@login_required
|
||||
def get_user_email():
|
||||
"""获取当前用户的邮箱信息"""
|
||||
user = database.get_user_by_id(current_user.id)
|
||||
if not user:
|
||||
return jsonify({"error": "用户不存在"}), 404
|
||||
|
||||
return jsonify({
|
||||
"email": user.get('email', ''),
|
||||
"email_verified": user.get('email_verified', False)
|
||||
})
|
||||
|
||||
|
||||
@app.route('/api/user/bind-email', methods=['POST'])
|
||||
@login_required
|
||||
@require_ip_not_locked
|
||||
def bind_user_email():
|
||||
"""发送邮箱绑定验证邮件"""
|
||||
data = request.get_json()
|
||||
email = data.get('email', '').strip().lower()
|
||||
|
||||
# 验证邮箱格式
|
||||
if not email or not validate_email(email):
|
||||
return jsonify({"error": "请输入有效的邮箱地址"}), 400
|
||||
|
||||
# 检查邮件功能是否启用
|
||||
settings = email_service.get_email_settings()
|
||||
if not settings.get('enabled', False):
|
||||
return jsonify({"error": "邮件功能未启用,请联系管理员"}), 400
|
||||
|
||||
# 检查邮箱是否已被其他用户使用
|
||||
existing_user = database.get_user_by_email(email)
|
||||
if existing_user and existing_user['id'] != current_user.id:
|
||||
return jsonify({"error": "该邮箱已被其他用户绑定"}), 400
|
||||
|
||||
# 获取当前用户信息
|
||||
user = database.get_user_by_id(current_user.id)
|
||||
if not user:
|
||||
return jsonify({"error": "用户不存在"}), 404
|
||||
|
||||
# 如果已经绑定了相同邮箱且已验证,无需重复绑定
|
||||
if user.get('email') == email and user.get('email_verified'):
|
||||
return jsonify({"error": "该邮箱已绑定并验证"}), 400
|
||||
|
||||
# 发送验证邮件
|
||||
result = email_service.send_bind_email_verification(
|
||||
user_id=current_user.id,
|
||||
email=email,
|
||||
username=user['username']
|
||||
)
|
||||
|
||||
if result['success']:
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "验证邮件已发送,请查收"
|
||||
})
|
||||
else:
|
||||
return jsonify({"error": result['error']}), 500
|
||||
|
||||
|
||||
@app.route('/api/verify-bind-email/<token>')
|
||||
def verify_bind_email(token):
|
||||
"""验证邮箱绑定Token"""
|
||||
result = email_service.verify_bind_email_token(token)
|
||||
|
||||
if result:
|
||||
user_id = result['user_id']
|
||||
email = result['email']
|
||||
|
||||
# 更新用户邮箱
|
||||
if database.update_user_email(user_id, email, verified=True):
|
||||
# 返回成功页面
|
||||
return render_template('verify_success.html',
|
||||
title='邮箱绑定成功',
|
||||
message=f'邮箱 {email} 已成功绑定到您的账号!',
|
||||
redirect_url='/'
|
||||
)
|
||||
else:
|
||||
return render_template('verify_failed.html',
|
||||
title='绑定失败',
|
||||
message='邮箱绑定失败,请重试'
|
||||
)
|
||||
else:
|
||||
return render_template('verify_failed.html',
|
||||
title='链接无效',
|
||||
message='验证链接已过期或无效,请重新发送验证邮件'
|
||||
)
|
||||
|
||||
|
||||
@app.route('/api/user/unbind-email', methods=['POST'])
|
||||
@login_required
|
||||
def unbind_user_email():
|
||||
"""解绑用户邮箱"""
|
||||
user = database.get_user_by_id(current_user.id)
|
||||
if not user:
|
||||
return jsonify({"error": "用户不存在"}), 404
|
||||
|
||||
if not user.get('email'):
|
||||
return jsonify({"error": "当前未绑定邮箱"}), 400
|
||||
|
||||
# 解绑邮箱
|
||||
if database.update_user_email(current_user.id, None, verified=False):
|
||||
return jsonify({"success": True, "message": "邮箱已解绑"})
|
||||
else:
|
||||
return jsonify({"error": "解绑失败"}), 500
|
||||
|
||||
|
||||
@app.route('/api/run_stats', methods=['GET'])
|
||||
@login_required
|
||||
def get_run_stats():
|
||||
|
||||
Reference in New Issue
Block a user