添加是否开启注册开关

This commit is contained in:
zhinianboke 2025-08-05 15:03:38 +08:00
parent a87f1904c0
commit d53a114dba
5 changed files with 287 additions and 7 deletions

View File

@ -342,7 +342,8 @@ class DBManager:
# 插入默认系统设置不包括管理员密码由reply_server.py初始化
cursor.execute('''
INSERT OR IGNORE INTO system_settings (key, value, description) VALUES
('theme_color', 'blue', '主题颜色')
('theme_color', 'blue', '主题颜色'),
('registration_enabled', 'true', '是否开启用户注册')
''')
# 检查并升级数据库

View File

@ -85,6 +85,8 @@ class LoginResponse(BaseModel):
token: Optional[str] = None
message: str
user_id: Optional[int] = None
username: Optional[str] = None
is_admin: Optional[bool] = None
class ChangePasswordRequest(BaseModel):
@ -397,6 +399,33 @@ async def login_page():
# 注册页面路由
@app.get('/register.html', response_class=HTMLResponse)
async def register_page():
# 检查注册是否开启
from db_manager import db_manager
registration_enabled = db_manager.get_system_setting('registration_enabled')
if registration_enabled != 'true':
return HTMLResponse('''
<!DOCTYPE html>
<html>
<head>
<title>注册已关闭</title>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
.message { color: #666; font-size: 18px; }
.back-link { margin-top: 20px; }
.back-link a { color: #007bff; text-decoration: none; }
</style>
</head>
<body>
<h2>🚫 注册功能已关闭</h2>
<p class="message">系统管理员已关闭用户注册功能</p>
<div class="back-link">
<a href="/"> 返回首页</a>
</div>
</body>
</html>
''', status_code=403)
register_path = os.path.join(static_dir, 'register.html')
if os.path.exists(register_path):
with open(register_path, 'r', encoding='utf-8') as f:
@ -491,7 +520,9 @@ async def login(request: LoginRequest):
success=True,
token=token,
message="登录成功",
user_id=user['id']
user_id=user['id'],
username=user['username'],
is_admin=(user['username'] == ADMIN_USERNAME)
)
logger.warning(f"{request.username}】登录失败:用户名或密码错误")
@ -520,7 +551,9 @@ async def login(request: LoginRequest):
success=True,
token=token,
message="登录成功",
user_id=user['id']
user_id=user['id'],
username=user['username'],
is_admin=(user['username'] == ADMIN_USERNAME)
)
logger.warning(f"{request.email}】邮箱登录失败:邮箱或密码错误")
@ -564,7 +597,9 @@ async def login(request: LoginRequest):
success=True,
token=token,
message="登录成功",
user_id=user['id']
user_id=user['id'],
username=user['username'],
is_admin=(user['username'] == ADMIN_USERNAME)
)
else:
@ -581,7 +616,8 @@ async def verify(user_info: Optional[Dict[str, Any]] = Depends(verify_token)):
return {
"authenticated": True,
"user_id": user_info['user_id'],
"username": user_info['username']
"username": user_info['username'],
"is_admin": user_info['username'] == ADMIN_USERNAME
}
return {"authenticated": False}
@ -759,6 +795,15 @@ async def send_verification_code(request: SendCodeRequest):
async def register(request: RegisterRequest):
from db_manager import db_manager
# 检查注册是否开启
registration_enabled = db_manager.get_system_setting('registration_enabled')
if registration_enabled != 'true':
logger.warning(f"{request.username}】注册失败: 注册功能已关闭")
return RegisterResponse(
success=False,
message="注册功能已关闭,请联系管理员"
)
try:
logger.info(f"{request.username}】尝试注册,邮箱: {request.email}")
@ -1420,6 +1465,66 @@ def update_system_setting(key: str, setting_data: SystemSettingIn, _: None = Dep
raise HTTPException(status_code=500, detail=str(e))
# ------------------------- 注册设置接口 -------------------------
@app.get('/registration-status')
def get_registration_status():
"""获取注册开关状态(公开接口,无需认证)"""
from db_manager import db_manager
try:
enabled_str = db_manager.get_system_setting('registration_enabled')
logger.info(f"从数据库获取的注册设置值: '{enabled_str}'") # 调试信息
# 如果设置不存在,默认为开启
if enabled_str is None:
enabled_bool = True
message = '注册功能已开启'
else:
enabled_bool = enabled_str == 'true'
message = '注册功能已开启' if enabled_bool else '注册功能已关闭'
logger.info(f"解析后的注册状态: enabled={enabled_bool}, message='{message}'") # 调试信息
return {
'enabled': enabled_bool,
'message': message
}
except Exception as e:
logger.error(f"获取注册状态失败: {e}")
return {'enabled': True, 'message': '注册功能已开启'} # 出错时默认开启
class RegistrationSettingUpdate(BaseModel):
enabled: bool
@app.put('/registration-settings')
def update_registration_settings(setting_data: RegistrationSettingUpdate, admin_user: Dict[str, Any] = Depends(require_admin)):
"""更新注册开关设置(仅管理员)"""
from db_manager import db_manager
try:
enabled = setting_data.enabled
success = db_manager.set_system_setting(
'registration_enabled',
'true' if enabled else 'false',
'是否开启用户注册'
)
if success:
log_with_user('info', f"更新注册设置: {'开启' if enabled else '关闭'}", admin_user)
return {
'success': True,
'enabled': enabled,
'message': f"注册功能已{'开启' if enabled else '关闭'}"
}
else:
raise HTTPException(status_code=500, detail='更新注册设置失败')
except HTTPException:
raise
except Exception as e:
logger.error(f"更新注册设置失败: {e}")
raise HTTPException(status_code=500, detail=str(e))

View File

@ -983,6 +983,41 @@
</div>
</div>
<!-- 注册设置 (仅管理员可见) -->
<div id="registration-settings" class="row mt-4" style="display: none;">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<i class="bi bi-person-plus me-2"></i>注册设置
<span class="badge bg-warning ms-2">管理员专用</span>
</div>
<div class="card-body">
<div class="mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="registrationEnabled">
<label class="form-check-label" for="registrationEnabled">
<strong>开启用户注册</strong>
</label>
</div>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>
关闭后,新用户将无法注册账号,登录页面也不会显示注册链接
</div>
</div>
<button type="button" class="btn btn-primary" onclick="updateRegistrationSettings()">
<i class="bi bi-check-circle me-1"></i>保存设置
</button>
<div id="registrationStatus" class="mt-3" style="display: none;">
<div class="alert alert-info mb-0">
<i class="bi bi-info-circle me-2"></i>
<span id="registrationStatusText"></span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 备份管理 (仅管理员可见) -->
<div id="backup-management" class="row mt-4" style="display: none;">
<div class="col-12">

View File

@ -76,6 +76,9 @@ function showSection(sectionName) {
case 'message-notifications': // 【消息通知菜单】
loadMessageNotifications();
break;
case 'system-settings': // 【系统设置菜单】
loadSystemSettings();
break;
case 'logs': // 【日志管理菜单】
// 如果没有日志数据,则加载
setTimeout(() => {
@ -1649,7 +1652,7 @@ async function checkAuth() {
}
// 检查是否为管理员,显示管理员菜单和功能
if (result.username === 'admin') {
if (result.is_admin === true) {
const adminMenuSection = document.getElementById('adminMenuSection');
if (adminMenuSection) {
adminMenuSection.style.display = 'block';
@ -1660,6 +1663,12 @@ async function checkAuth() {
if (backupManagement) {
backupManagement.style.display = 'block';
}
// 显示注册设置功能
const registrationSettings = document.getElementById('registration-settings');
if (registrationSettings) {
registrationSettings.style.display = 'block';
}
}
return true;
@ -6473,3 +6482,105 @@ function editRemark(cookieId, currentRemark) {
input.focus();
input.select();
}
// ==================== 系统设置功能 ====================
// 加载系统设置
async function loadSystemSettings() {
console.log('加载系统设置');
// 通过验证接口获取用户信息(更可靠)
try {
const response = await fetch(`${apiBase}/verify`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
});
if (response.ok) {
const result = await response.json();
const isAdmin = result.is_admin === true;
console.log('用户信息:', result, '是否管理员:', isAdmin);
// 显示/隐藏注册设置(仅管理员可见)
const registrationSettings = document.getElementById('registration-settings');
if (registrationSettings) {
registrationSettings.style.display = isAdmin ? 'block' : 'none';
}
// 如果是管理员,加载注册设置
if (isAdmin) {
await loadRegistrationSettings();
}
}
} catch (error) {
console.error('获取用户信息失败:', error);
// 出错时隐藏管理员功能
const registrationSettings = document.getElementById('registration-settings');
if (registrationSettings) {
registrationSettings.style.display = 'none';
}
}
}
// 加载注册设置
async function loadRegistrationSettings() {
try {
const response = await fetch('/registration-status');
if (response.ok) {
const data = await response.json();
const checkbox = document.getElementById('registrationEnabled');
if (checkbox) {
checkbox.checked = data.enabled;
}
}
} catch (error) {
console.error('加载注册设置失败:', error);
showToast('加载注册设置失败', 'danger');
}
}
// 更新注册设置
async function updateRegistrationSettings() {
const checkbox = document.getElementById('registrationEnabled');
const statusDiv = document.getElementById('registrationStatus');
const statusText = document.getElementById('registrationStatusText');
if (!checkbox) return;
const enabled = checkbox.checked;
try {
const response = await fetch('/registration-settings', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`
},
body: JSON.stringify({ enabled: enabled })
});
if (response.ok) {
const data = await response.json();
showToast(data.message, 'success');
// 显示状态信息
if (statusDiv && statusText) {
statusText.textContent = data.message;
statusDiv.style.display = 'block';
// 3秒后隐藏状态信息
setTimeout(() => {
statusDiv.style.display = 'none';
}, 3000);
}
} else {
const errorData = await response.json();
showToast(`更新失败: ${errorData.detail || '未知错误'}`, 'danger');
}
} catch (error) {
console.error('更新注册设置失败:', error);
showToast('更新注册设置失败', 'danger');
}
}

View File

@ -218,7 +218,7 @@
</form>
<!-- 注册链接 -->
<div class="text-center mt-3">
<div id="registerSection" class="text-center mt-3">
<span class="text-muted">还没有账号?</span>
<a href="/register.html" class="text-decoration-none">
<i class="bi bi-person-plus me-1"></i>立即注册
@ -377,6 +377,14 @@
// 保存token到localStorage
localStorage.setItem('auth_token', result.token);
// 保存用户信息到localStorage
const userInfo = {
user_id: result.user_id,
username: result.username,
is_admin: result.is_admin
};
localStorage.setItem('user_info', JSON.stringify(userInfo));
// 检查是否有重定向URL
const redirectUrl = localStorage.getItem('redirectAfterLogin');
if (redirectUrl) {
@ -634,8 +642,28 @@
}
}
// 检查注册状态
async function checkRegistrationStatus() {
try {
const response = await fetch('/registration-status');
if (response.ok) {
const data = await response.json();
const registerSection = document.getElementById('registerSection');
if (registerSection) {
registerSection.style.display = data.enabled ? 'block' : 'none';
}
}
} catch (error) {
console.error('检查注册状态失败:', error);
// 出错时默认显示注册链接
}
}
// 事件监听器
document.addEventListener('DOMContentLoaded', function() {
// 检查注册状态
checkRegistrationStatus();
// 登录方式切换
document.querySelectorAll('input[name="loginType"]').forEach(radio => {
radio.addEventListener('change', switchLoginType);