个股论坛重做

This commit is contained in:
2026-01-06 12:44:35 +08:00
parent 42855274cc
commit 915bfca3d6
2 changed files with 298 additions and 1 deletions

View File

@@ -136,6 +136,120 @@ def admin_required(permission=None):
return decorator
def get_channel_admin_info(channel_id, user_id):
"""获取用户在指定频道的管理员信息"""
# 先检查是否是超级管理员
super_admin = get_user_admin_info(user_id)
if super_admin and super_admin['isAdmin']:
return {
'role': 'super_admin',
'isSuperAdmin': True,
'isOwner': True,
'isAdmin': True,
'isModerator': True,
'permissions': {
'delete_channel': True,
'edit_channel': True,
'manage_admins': True,
'pin_messages': True,
'delete_messages': True,
'slow_mode': True,
'lock_channel': True
}
}
# 检查频道管理员
try:
with get_db_engine().connect() as conn:
sql = text("""
SELECT role, permissions
FROM community_channel_admins
WHERE channel_id = :channel_id AND user_id = :user_id
""")
result = conn.execute(sql, {
'channel_id': channel_id,
'user_id': int(user_id)
}).fetchone()
if result:
import json
permissions = result.permissions
if isinstance(permissions, str):
permissions = json.loads(permissions)
role = result.role
return {
'role': role,
'isSuperAdmin': False,
'isOwner': role == 'owner',
'isAdmin': role in ['owner', 'admin'],
'isModerator': role in ['owner', 'admin', 'moderator'],
'permissions': permissions or {}
}
except Exception as e:
print(f"[Community API] 获取频道管理员信息失败: {e}")
return None
def check_channel_permission(channel_id, user_id, permission):
"""检查用户是否有指定频道的权限"""
admin_info = get_channel_admin_info(channel_id, user_id)
if not admin_info:
return False
if admin_info['isSuperAdmin'] or admin_info['isOwner']:
return True
return admin_info['permissions'].get(permission, False)
def add_channel_admin(channel_id, user_id, role='owner'):
"""添加频道管理员"""
try:
with get_db_engine().connect() as conn:
# 根据角色设置默认权限
permissions = {}
if role == 'owner':
permissions = {
'delete_channel': True,
'edit_channel': True,
'manage_admins': True,
'pin_messages': True,
'delete_messages': True,
'slow_mode': True,
'lock_channel': True
}
elif role == 'admin':
permissions = {
'edit_channel': True,
'pin_messages': True,
'delete_messages': True,
'slow_mode': True
}
elif role == 'moderator':
permissions = {
'pin_messages': True,
'delete_messages': True
}
import json
sql = text("""
INSERT INTO community_channel_admins (channel_id, user_id, role, permissions)
VALUES (:channel_id, :user_id, :role, :permissions)
ON DUPLICATE KEY UPDATE role = :role, permissions = :permissions
""")
conn.execute(sql, {
'channel_id': channel_id,
'user_id': int(user_id),
'role': role,
'permissions': json.dumps(permissions)
})
conn.commit()
return True
except Exception as e:
print(f"[Community API] 添加频道管理员失败: {e}")
return False
def api_response(data=None, message='success', code=200):
"""统一 API 响应格式"""
return jsonify({
@@ -180,6 +294,136 @@ def get_my_admin_status():
})
@community_bp.route('/channels/<channel_id>/admin-status', methods=['GET'])
@login_required
def get_channel_admin_status(channel_id):
"""获取当前用户在指定频道的管理员状态"""
user = g.current_user
admin_info = get_channel_admin_info(channel_id, user['id'])
if admin_info:
return api_response({
'role': admin_info['role'],
'isSuperAdmin': admin_info['isSuperAdmin'],
'isOwner': admin_info['isOwner'],
'isAdmin': admin_info['isAdmin'],
'isModerator': admin_info['isModerator'],
'permissions': admin_info['permissions']
})
else:
return api_response({
'role': None,
'isSuperAdmin': False,
'isOwner': False,
'isAdmin': False,
'isModerator': False,
'permissions': {}
})
@community_bp.route('/channels/<channel_id>/admins', methods=['GET'])
@login_required
def get_channel_admins(channel_id):
"""获取频道管理员列表"""
try:
with get_db_engine().connect() as conn:
sql = text("""
SELECT cca.user_id, cca.role, cca.permissions, cca.created_at,
u.username, u.avatar
FROM community_channel_admins cca
LEFT JOIN users u ON cca.user_id = u.id
WHERE cca.channel_id = :channel_id
ORDER BY
CASE cca.role
WHEN 'owner' THEN 1
WHEN 'admin' THEN 2
WHEN 'moderator' THEN 3
END
""")
result = conn.execute(sql, {'channel_id': channel_id}).fetchall()
admins = []
for row in result:
import json
permissions = row.permissions
if isinstance(permissions, str):
permissions = json.loads(permissions)
admins.append({
'userId': str(row.user_id),
'username': row.username,
'avatar': row.avatar,
'role': row.role,
'permissions': permissions or {},
'createdAt': row.created_at.isoformat() if row.created_at else None
})
return api_response(admins)
except Exception as e:
print(f"[Community API] 获取频道管理员列表失败: {e}")
return api_error(f'获取管理员列表失败: {str(e)}', 500)
@community_bp.route('/channels/<channel_id>/admins', methods=['POST'])
@login_required
def add_channel_admin_api(channel_id):
"""添加频道管理员(需要 owner 或超级管理员权限)"""
user = g.current_user
# 检查权限
if not check_channel_permission(channel_id, user['id'], 'manage_admins'):
return api_error('无权限管理频道管理员', 403)
data = request.get_json()
target_user_id = data.get('userId')
role = data.get('role', 'moderator')
if not target_user_id:
return api_error('请指定用户ID')
if role not in ['admin', 'moderator']:
return api_error('无效的角色,只能设置 admin 或 moderator')
# 不能设置为 ownerowner 只能是创建者)
if add_channel_admin(channel_id, target_user_id, role):
return api_response({'success': True, 'message': f'已添加 {role}'})
else:
return api_error('添加管理员失败', 500)
@community_bp.route('/channels/<channel_id>/admins/<user_id>', methods=['DELETE'])
@login_required
def remove_channel_admin_api(channel_id, user_id):
"""移除频道管理员(需要 owner 或超级管理员权限)"""
current_user = g.current_user
# 检查权限
if not check_channel_permission(channel_id, current_user['id'], 'manage_admins'):
return api_error('无权限管理频道管理员', 403)
# 不能移除 owner
target_admin = get_channel_admin_info(channel_id, user_id)
if target_admin and target_admin['isOwner'] and not target_admin['isSuperAdmin']:
return api_error('不能移除频道创建者', 400)
try:
with get_db_engine().connect() as conn:
sql = text("""
DELETE FROM community_channel_admins
WHERE channel_id = :channel_id AND user_id = :user_id
""")
conn.execute(sql, {
'channel_id': channel_id,
'user_id': int(user_id)
})
conn.commit()
return api_response({'success': True, 'message': '已移除管理员'})
except Exception as e:
print(f"[Community API] 移除频道管理员失败: {e}")
return api_error(f'移除管理员失败: {str(e)}', 500)
# ============================================================
# 频道相关 API
# ============================================================
@@ -373,6 +617,9 @@ def create_channel():
})
conn.commit()
# 将创建者设为频道管理员owner
add_channel_admin(channel_id, user['id'], role='owner')
# 返回创建的频道信息
response_data = {
'id': channel_id,
@@ -387,9 +634,10 @@ def create_channel():
'subscriberCount': 0,
'messageCount': 0,
'createdAt': now.isoformat(),
'isOwner': True, # 创建者自动是 owner
}
print(f"[Community API] 创建频道成功: {channel_id} - {name}")
print(f"[Community API] 创建频道成功: {channel_id} - {name}, 创建者: {user['id']}")
return api_response(response_data)
except Exception as e:

View File

@@ -0,0 +1,49 @@
-- 频道管理员表
-- 在 MySQL 中执行
-- 1. 创建频道管理员表
CREATE TABLE IF NOT EXISTS community_channel_admins (
id INT AUTO_INCREMENT PRIMARY KEY,
channel_id VARCHAR(50) NOT NULL,
user_id INT NOT NULL,
role ENUM('owner', 'admin', 'moderator') NOT NULL DEFAULT 'moderator',
-- owner: 频道创建者,拥有最高权限
-- admin: 频道管理员,可以管理消息和成员
-- moderator: 版主,可以删除消息
permissions JSON,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_channel_user (channel_id, user_id),
INDEX idx_channel_id (channel_id),
INDEX idx_user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 2. 权限说明
-- owner 权限(频道创建者):
-- - delete_channel: 删除频道
-- - edit_channel: 编辑频道信息
-- - manage_admins: 管理频道管理员
-- - pin_messages: 置顶消息
-- - delete_messages: 删除任何消息
-- - slow_mode: 设置慢速模式
-- - lock_channel: 锁定频道
-- admin 权限:
-- - edit_channel: 编辑频道信息(部分)
-- - pin_messages: 置顶消息
-- - delete_messages: 删除消息
-- - slow_mode: 设置慢速模式
-- moderator 权限:
-- - pin_messages: 置顶消息
-- - delete_messages: 删除消息
-- 3. 超级管理员说明
-- community_admins 表中 role='admin' 的用户(如 user_id=65
-- 自动拥有所有频道的最高权限,不需要在此表中添加记录
-- 查看频道管理员
-- SELECT cca.*, u.username, c.name as channel_name
-- FROM community_channel_admins cca
-- LEFT JOIN users u ON cca.user_id = u.id
-- LEFT JOIN community_channels c ON cca.channel_id = c.id;