Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions management/server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from flask import Flask, request
from flask_cors import CORS
from routes import register_routes
from services.users.service import authenticate_user

# 加载环境变量
load_dotenv(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "docker", ".env"))
Expand Down Expand Up @@ -41,12 +42,19 @@


# 生成token
def generate_token(username):
def generate_token(user_info):
# 设置令牌过期时间(例如1小时后过期)
expire_time = datetime.utcnow() + timedelta(hours=1)

# 生成令牌
token = jwt.encode({"username": username, "exp": expire_time}, JWT_SECRET, algorithm="HS256")
# 生成令牌,包含用户ID、用户名、角色和租户ID
payload = {
"user_id": user_info['id'],
"username": user_info['username'],
"role": user_info['role'],
"tenant_id": user_info.get('tenant_id'),
"exp": expire_time
}
token = jwt.encode(payload, JWT_SECRET, algorithm="HS256")

return token

Expand All @@ -58,19 +66,17 @@ def login():
username = data.get("username")
password = data.get("password")

# 创建用户名和密码的映射
valid_users = {ADMIN_USERNAME: ADMIN_PASSWORD}
if not username or not password:
return {"code": 1, "message": "用户名和密码不能为空"}, 400

# 验证用户名是否存在
if not username or username not in valid_users:
return {"code": 1, "message": "用户名不存在"}, 400
# 从数据库验证用户,只允许超级管理员和团队负责人登录
success, user_info, error_message = authenticate_user(username, password)

# 验证密码是否正确
if not password or password != valid_users[username]:
return {"code": 1, "message": "密码错误"}, 400
if not success:
return {"code": 1, "message": error_message}, 400

# 生成token
token = generate_token(username)
token = generate_token(user_info)

return {"code": 0, "data": {"token": token}, "message": "登录成功"}

Expand Down
18 changes: 16 additions & 2 deletions management/server/routes/files/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from flask import current_app, jsonify, request, send_file
from services.files.service import batch_delete_files, delete_file, download_file_from_minio, get_file_info, get_files_list, handle_chunk_upload, merge_chunks, upload_files_to_server
from services.files.utils import FileType
from services.auth import get_current_user_from_token, is_admin

from .. import files_bp

Expand All @@ -19,8 +20,12 @@ def upload_file():
if "files" not in request.files:
return jsonify({"code": 400, "message": "未选择文件", "data": None}), 400

# 获取当前用户信息
current_user = get_current_user_from_token()
user_id = current_user.get('user_id') if current_user else None

files = request.files.getlist("files")
upload_result = upload_files_to_server(files)
upload_result = upload_files_to_server(files, user_id=user_id)

# 返回标准格式
return jsonify({"code": 0, "message": "上传成功", "data": upload_result["data"]})
Expand All @@ -33,13 +38,22 @@ def get_files():
return "", 200

try:
# 获取当前用户信息
current_user = get_current_user_from_token()

current_page = int(request.args.get("currentPage", 1))
page_size = int(request.args.get("size", 10))
name_filter = request.args.get("name", "")
sort_by = request.args.get("sort_by", "create_time")
sort_order = request.args.get("sort_order", "desc")

result, total = get_files_list(current_page, page_size, name_filter, sort_by, sort_order)
# 根据用户角色过滤文件
# 超级管理员可以看到所有文件,团队负责人只能看到自己上传的文件
user_id = None
if current_user and not is_admin(current_user):
user_id = current_user.get('user_id')

result, total = get_files_list(current_page, page_size, name_filter, sort_by, sort_order, user_id)

return jsonify({"code": 0, "data": {"list": result, "total": total}, "message": "获取文件列表成功"})

Expand Down
9 changes: 9 additions & 0 deletions management/server/routes/knowledgebases/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from flask import request
from services.knowledgebases.service import KnowledgebaseService
from services.auth import get_current_user_from_token, is_admin
from utils import error_response, success_response

from .. import knowledgebase_bp
Expand All @@ -11,13 +12,21 @@
def get_knowledgebase_list():
"""获取知识库列表"""
try:
# 获取当前用户信息
current_user = get_current_user_from_token()

params = {
"page": int(request.args.get("currentPage", 1)),
"size": int(request.args.get("size", 10)),
"name": request.args.get("name", ""),
"sort_by": request.args.get("sort_by", "create_time"),
"sort_order": request.args.get("sort_order", "desc"),
}

# 如果是团队负责人,只返回其租户的知识库
if current_user and not is_admin(current_user):
params["tenant_id"] = current_user.get("tenant_id")

result = KnowledgebaseService.get_knowledgebase_list(**params)
return success_response(result)
except ValueError:
Expand Down
11 changes: 10 additions & 1 deletion management/server/routes/teams/routes.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
from flask import jsonify, request
from services.teams.service import get_teams_with_pagination, get_team_by_id, delete_team, get_team_members, add_team_member, remove_team_member
from services.auth import get_current_user_from_token, is_admin
from .. import teams_bp

@teams_bp.route('', methods=['GET'])
def get_teams():
"""获取团队列表的API端点,支持分页和条件查询"""
try:
# 获取当前用户信息
current_user = get_current_user_from_token()

# 获取查询参数
current_page = int(request.args.get('currentPage', 1))
page_size = int(request.args.get('size', 10))
team_name = request.args.get('name', '')
sort_by = request.args.get("sort_by", "create_time")
sort_order = request.args.get("sort_order", "desc")

# 如果是团队负责人,只返回其自己的团队
tenant_id = None
if current_user and not is_admin(current_user):
tenant_id = current_user.get("tenant_id")

# 调用服务函数获取分页和筛选后的团队数据
teams, total = get_teams_with_pagination(current_page, page_size, team_name, sort_by, sort_order)
teams, total = get_teams_with_pagination(current_page, page_size, team_name, sort_by, sort_order, tenant_id)

# 返回符合前端期望格式的数据
return jsonify({
Expand Down
54 changes: 45 additions & 9 deletions management/server/routes/users/routes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import os
import jwt
from flask import jsonify, request
from services.users.service import get_users_with_pagination, delete_user, create_user, update_user, reset_user_password
from services.users.service import get_users_with_pagination, delete_user, create_user, update_user, reset_user_password, get_user_info_by_id
from .. import users_bp

JWT_SECRET = os.getenv("MANAGEMENT_JWT_SECRET", "your-secret-key")

@users_bp.route('', methods=['GET'])
def get_users():
"""获取用户的API端点,支持分页和条件查询"""
Expand Down Expand Up @@ -78,14 +82,46 @@ def update_user_route(user_id):

@users_bp.route('/me', methods=['GET'])
def get_current_user():
return jsonify({
"code": 0,
"data": {
"username": "admin",
"roles": ["admin"]
},
"message": "获取用户信息成功"
})
"""获取当前登录用户信息"""
try:
# 从请求头获取token
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({"code": 401, "message": "未提供有效的认证令牌"}), 401

token = auth_header.split(' ')[1]

# 解析token
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
except jwt.ExpiredSignatureError:
return jsonify({"code": 401, "message": "令牌已过期"}), 401
except jwt.InvalidTokenError:
return jsonify({"code": 401, "message": "无效的令牌"}), 401

user_id = payload.get('user_id')

# 从数据库获取用户信息
user_info = get_user_info_by_id(user_id)

if not user_info:
return jsonify({"code": 401, "message": "用户不存在或无权限"}), 401

return jsonify({
"code": 0,
"data": {
"username": user_info['username'],
"roles": user_info['roles'],
"role": user_info['role'],
"tenant_id": user_info.get('tenant_id')
},
"message": "获取用户信息成功"
})
except Exception as e:
return jsonify({
"code": 500,
"message": f"获取用户信息失败: {str(e)}"
}), 500

@users_bp.route('/<string:user_id>/reset-password', methods=['PUT'])
def reset_password_route(user_id):
Expand Down
1 change: 1 addition & 0 deletions management/server/services/auth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .auth_utils import get_current_user_from_token, is_admin, is_team_owner
47 changes: 47 additions & 0 deletions management/server/services/auth/auth_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import os
import jwt
from flask import request

JWT_SECRET = os.getenv("MANAGEMENT_JWT_SECRET", "your-secret-key")


def get_current_user_from_token():
"""
从请求头的JWT token中获取当前用户信息
返回: dict 包含 user_id, username, role, tenant_id 或 None
"""
try:
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return None

token = auth_header.split(' ')[1]

try:
payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
return {
'user_id': payload.get('user_id'),
'username': payload.get('username'),
'role': payload.get('role'),
'tenant_id': payload.get('tenant_id')
}
except jwt.ExpiredSignatureError:
return None
except jwt.InvalidTokenError:
return None
except Exception:
return None


def is_admin(user_info):
"""检查用户是否是超级管理员"""
if not user_info:
return False
return user_info.get('role') == 'admin'


def is_team_owner(user_info):
"""检查用户是否是团队负责人"""
if not user_info:
return False
return user_info.get('role') == 'team_owner'
11 changes: 9 additions & 2 deletions management/server/services/files/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ def filename_type(filename):
return FileType.OTHER.value


def get_files_list(current_page, page_size, name_filter="", sort_by="create_time", sort_order="desc"):
def get_files_list(current_page, page_size, name_filter="", sort_by="create_time", sort_order="desc", user_id=None):
"""
获取文件列表

Args:
current_page: 当前页码
page_size: 每页大小
parent_id: 父文件夹ID
name_filter: 文件名过滤条件
sort_by: 排序字段
sort_order: 排序顺序
user_id: 用户ID(如果提供,则只返回该用户上传的文件)

Returns:
tuple: (文件列表, 总数)
Expand All @@ -77,6 +79,11 @@ def get_files_list(current_page, page_size, name_filter="", sort_by="create_time
if name_filter:
where_clause += " AND f.name LIKE %s"
params.append(f"%{name_filter}%")

# 如果提供了user_id,则只返回该用户上传的文件
if user_id:
where_clause += " AND f.created_by = %s"
params.append(user_id)

# 验证排序字段
valid_sort_fields = ["name", "size", "type", "create_time", "create_date"]
Expand Down
35 changes: 28 additions & 7 deletions management/server/services/knowledgebases/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ def _get_db_connection(cls):
return mysql.connector.connect(**DB_CONFIG)

@classmethod
def get_knowledgebase_list(cls, page=1, size=10, name="", sort_by="create_time", sort_order="desc"):
"""获取知识库列表"""
def get_knowledgebase_list(cls, page=1, size=10, name="", sort_by="create_time", sort_order="desc", tenant_id=None):
"""
获取知识库列表
tenant_id: 如果提供,则只返回该租户相关的知识库
"""
conn = cls._get_db_connection()
cursor = conn.cursor(dictionary=True)

Expand All @@ -49,16 +52,26 @@ def get_knowledgebase_list(cls, page=1, size=10, name="", sort_by="create_time",
k.language,
k.permission,
k.created_by,
k.tenant_id,
u.nickname
FROM knowledgebase k
LEFT JOIN user u ON k.created_by = u.id -- 获取创建者的昵称
LEFT JOIN user u ON k.created_by = u.id
"""
params = []
where_clauses = []

if name:
query += " WHERE k.name LIKE %s"
where_clauses.append("k.name LIKE %s")
params.append(f"%{name}%")

# 如果提供了tenant_id,则只返回该租户的知识库
if tenant_id:
where_clauses.append("k.tenant_id = %s")
params.append(tenant_id)

if where_clauses:
query += " WHERE " + " AND ".join(where_clauses)

# 添加查询排序条件
query += f" {sort_clause}"

Expand Down Expand Up @@ -87,10 +100,18 @@ def get_knowledgebase_list(cls, page=1, size=10, name="", sort_by="create_time",
result['nickname'] = "未知用户"

# 获取总数
count_query = "SELECT COUNT(*) as total FROM knowledgebase"
count_query = "SELECT COUNT(*) as total FROM knowledgebase k"
count_params = []
count_where_clauses = []
if name:
count_query += " WHERE name LIKE %s"
cursor.execute(count_query, params[:1] if name else [])
count_where_clauses.append("k.name LIKE %s")
count_params.append(f"%{name}%")
if tenant_id:
count_where_clauses.append("k.tenant_id = %s")
count_params.append(tenant_id)
if count_where_clauses:
count_query += " WHERE " + " AND ".join(count_where_clauses)
cursor.execute(count_query, count_params)
total = cursor.fetchone()["total"]

cursor.close()
Expand Down
Loading