处理超时和获取个人资料相关
This commit is contained in:
parent
58d0c021b3
commit
d769f814b4
@ -13,7 +13,8 @@ from .views import (
|
||||
RegisterView,
|
||||
LoginView,
|
||||
LogoutView,
|
||||
ChatHistoryViewSet
|
||||
ChatHistoryViewSet,
|
||||
user_profile
|
||||
)
|
||||
|
||||
# 创建路由器
|
||||
@ -39,6 +40,7 @@ urlpatterns = [
|
||||
|
||||
# 用户管理相关
|
||||
path('users/', user_list, name='user-list'),
|
||||
path('users/profile/', user_profile, name='user-profile'),
|
||||
path('users/<str:pk>/', user_detail, name='user-detail'),
|
||||
path('users/<str:pk>/update/', user_update, name='user-update'),
|
||||
path('users/<str:pk>/delete/', user_delete, name='user-delete'),
|
||||
|
@ -803,8 +803,7 @@ class ChatHistoryViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
},
|
||||
"problem_optimization": False
|
||||
},
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
|
||||
if chat_response.status_code != 200:
|
||||
@ -832,8 +831,7 @@ class ChatHistoryViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
url=message_url,
|
||||
json={"message": question, "re_chat": False, "stream": True},
|
||||
headers={"Content-Type": "application/json"},
|
||||
stream=True, # 启用流式传输
|
||||
timeout=60
|
||||
stream=True # 启用流式传输
|
||||
)
|
||||
|
||||
if message_request.status_code != 200:
|
||||
@ -1010,8 +1008,7 @@ class ChatHistoryViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
chat_response = requests.post(
|
||||
url=f"{settings.API_BASE_URL}/api/application/chat/open",
|
||||
json=chat_request_data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
|
||||
logger.info(f"API响应状态码: {chat_response.status_code}")
|
||||
@ -1041,8 +1038,7 @@ class ChatHistoryViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
message_response = requests.post(
|
||||
url=f"{settings.API_BASE_URL}/api/application/chat_message/{chat_id}",
|
||||
json=message_request_data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=60
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
|
||||
if message_response.status_code != 200:
|
||||
@ -1299,7 +1295,6 @@ class ChatHistoryViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
|
||||
export_response = requests.get(
|
||||
url=export_url,
|
||||
timeout=60,
|
||||
stream=True # 使用流式传输处理大文件
|
||||
)
|
||||
|
||||
@ -1356,8 +1351,7 @@ class ChatHistoryViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
# 调用外部API
|
||||
response = requests.get(
|
||||
url=api_url,
|
||||
params=params,
|
||||
timeout=30
|
||||
params=params
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
@ -1543,8 +1537,7 @@ class ChatHistoryViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
|
||||
response = requests.get(
|
||||
url=url,
|
||||
params=params,
|
||||
timeout=30
|
||||
params=params
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
@ -2067,8 +2060,7 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
response = requests.put(
|
||||
f'{settings.API_BASE_URL}/api/dataset/{instance.external_id}',
|
||||
json=api_data,
|
||||
headers={'Content-Type': 'application/json'},
|
||||
timeout=30
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
@ -2080,8 +2072,6 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
|
||||
logger.info(f"外部知识库更新成功: {instance.external_id}")
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
raise ExternalAPIError("请求超时,请稍后重试")
|
||||
except requests.exceptions.RequestException as e:
|
||||
raise ExternalAPIError(f"API请求失败: {str(e)}")
|
||||
except Exception as e:
|
||||
@ -2622,11 +2612,10 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
logger.info(f"调用分割API URL: {url}")
|
||||
logger.info(f"请求字段: {list(files_data.keys())}")
|
||||
|
||||
# 发送请求
|
||||
# 发送请求 - 移除timeout参数
|
||||
response = requests.post(
|
||||
url,
|
||||
files=files_data,
|
||||
timeout=60
|
||||
files=files_data
|
||||
)
|
||||
|
||||
# 记录请求头和响应信息,方便排查问题
|
||||
@ -2758,7 +2747,7 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
try:
|
||||
# 简单的验证请求
|
||||
verify_url = f'{settings.API_BASE_URL}/api/dataset/{instance.external_id}'
|
||||
verify_response = requests.get(verify_url, timeout=10)
|
||||
verify_response = requests.get(verify_url)
|
||||
if verify_response.status_code != 200:
|
||||
logger.error(f"外部知识库不存在或无法访问: {instance.external_id}, 状态码: {verify_response.status_code}")
|
||||
return Response({
|
||||
@ -2919,7 +2908,7 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
# 记录请求数据,方便调试
|
||||
logger.info(f"上传文档数据: 文档名={doc_data.get('name')}, 段落数={len(doc_data.get('paragraphs', []))}")
|
||||
|
||||
# 发送请求
|
||||
# 发送请求,不设置超时限制
|
||||
response = requests.post(url, json=doc_data)
|
||||
|
||||
# 记录响应结果
|
||||
@ -2996,8 +2985,7 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
response = requests.post(
|
||||
f'{settings.API_BASE_URL}/api/dataset',
|
||||
json=api_data,
|
||||
headers={'Content-Type': 'application/json'},
|
||||
timeout=30
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
@ -3013,8 +3001,6 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
|
||||
return dataset_id
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
raise ExternalAPIError("请求超时,请稍后重试")
|
||||
except requests.exceptions.RequestException as e:
|
||||
raise ExternalAPIError(f"API请求失败: {str(e)}")
|
||||
except Exception as e:
|
||||
@ -3028,8 +3014,7 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
|
||||
response = requests.delete(
|
||||
f'{settings.API_BASE_URL}/api/dataset/{external_id}',
|
||||
headers={'Content-Type': 'application/json'},
|
||||
timeout=30
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
logger.info(f"删除外部知识库响应: status_code={response.status_code}, response={response.text}")
|
||||
@ -3058,9 +3043,6 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
logger.warning(f"外部知识库删除响应无法解析JSON,但状态码为200,视为成功: {external_id}")
|
||||
return True
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
logger.error(f"删除外部知识库超时: {external_id}")
|
||||
raise ExternalAPIError("请求超时,请稍后重试")
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"删除外部知识库请求异常: {external_id}, error={str(e)}")
|
||||
raise ExternalAPIError(f"API请求失败: {str(e)}")
|
||||
@ -3096,8 +3078,7 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
url = f'{settings.API_BASE_URL}/api/dataset/{instance.external_id}/document'
|
||||
response = requests.get(
|
||||
url,
|
||||
headers={'Content-Type': 'application/json'},
|
||||
timeout=30
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
@ -3224,7 +3205,7 @@ class KnowledgeBaseViewSet(KnowledgeBasePermissionMixin, viewsets.ModelViewSet):
|
||||
# 调用正确的外部API获取文档段落内容
|
||||
try:
|
||||
url = f'{settings.API_BASE_URL}/api/dataset/{knowledge_base.external_id}/document/{document.external_id}/paragraph'
|
||||
response = requests.get(url, timeout=30)
|
||||
response = requests.get(url)
|
||||
|
||||
if response.status_code != 200:
|
||||
logger.error(f"获取文档段落内容失败: {response.status_code}, {response.text}")
|
||||
@ -4239,6 +4220,9 @@ class LoginView(APIView):
|
||||
# 获取或创建token
|
||||
token, _ = Token.objects.get_or_create(user=user)
|
||||
|
||||
# 登录用户(可选)
|
||||
login(request, user)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "登录成功",
|
||||
@ -4246,9 +4230,9 @@ class LoginView(APIView):
|
||||
"id": str(user.id),
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"name": user.name,
|
||||
"role": user.role,
|
||||
"department": user.department,
|
||||
"name": user.name,
|
||||
"group": user.group,
|
||||
"token": token.key
|
||||
}
|
||||
@ -4381,7 +4365,7 @@ class RegisterView(APIView):
|
||||
"code": 200,
|
||||
"message": "注册成功",
|
||||
"data": {
|
||||
"id": user.id,
|
||||
"id": str(user.id),
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"role": user.role,
|
||||
@ -4430,28 +4414,111 @@ class LogoutView(APIView):
|
||||
@api_view(['GET', 'PUT'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def user_profile(request):
|
||||
"""获取或更新用户信息"""
|
||||
if request.method == 'GET':
|
||||
data = {
|
||||
'id': request.user.id,
|
||||
'username': request.user.username,
|
||||
'email': request.user.email,
|
||||
'role': request.user.role,
|
||||
'department': request.user.department,
|
||||
'phone': request.user.phone,
|
||||
'date_joined': request.user.date_joined
|
||||
}
|
||||
return Response(data)
|
||||
"""
|
||||
获取或更新当前登录用户信息
|
||||
|
||||
elif request.method == 'PUT':
|
||||
user = request.user
|
||||
# 只允许更新特定字段
|
||||
allowed_fields = ['email', 'phone', 'department']
|
||||
for field in allowed_fields:
|
||||
if field in request.data:
|
||||
setattr(user, field, request.data[field])
|
||||
user.save()
|
||||
return Response({'message': '用户信息更新成功'})
|
||||
此接口与user_update的区别:
|
||||
1. 任何已认证用户可访问
|
||||
2. 仅能更新当前登录用户自己的信息
|
||||
3. 不能修改角色等重要字段
|
||||
4. 不需要指定用户ID,自动使用当前用户
|
||||
"""
|
||||
try:
|
||||
if request.method == 'GET':
|
||||
# 检查用户是否已认证
|
||||
user = request.user
|
||||
if not user.is_authenticated:
|
||||
return Response({
|
||||
'code': 401,
|
||||
'message': '用户未认证',
|
||||
'data': None
|
||||
}, status=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
data = {
|
||||
'id': str(user.id),
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'name': user.name,
|
||||
'role': user.role,
|
||||
'department': user.department,
|
||||
'group': user.group,
|
||||
'date_joined': user.date_joined.strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
return Response({
|
||||
'code': 200,
|
||||
'message': '获取用户信息成功',
|
||||
'data': data
|
||||
})
|
||||
|
||||
elif request.method == 'PUT':
|
||||
# 检查请求数据格式
|
||||
try:
|
||||
if not request.data:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '请求数据为空或格式错误',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
except Exception as data_error:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': f'请求数据格式错误: {str(data_error)}。请确保提交的是有效的JSON格式数据,属性名必须使用双引号。',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
user = request.user
|
||||
# 只允许更新特定字段
|
||||
allowed_fields = ['email', 'name', 'phone', 'department', 'group']
|
||||
updated_fields = []
|
||||
|
||||
for field in allowed_fields:
|
||||
if field in request.data:
|
||||
setattr(user, field, request.data[field])
|
||||
updated_fields.append(field)
|
||||
|
||||
if updated_fields:
|
||||
try:
|
||||
user.save()
|
||||
return Response({
|
||||
'code': 200,
|
||||
'message': f'用户信息更新成功,已更新字段: {", ".join(updated_fields)}',
|
||||
'data': {
|
||||
'id': str(user.id),
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'name': user.name,
|
||||
'role': user.role,
|
||||
'department': user.department,
|
||||
'group': user.group,
|
||||
}
|
||||
})
|
||||
except Exception as save_error:
|
||||
logger.error(f"保存用户数据失败: {str(save_error)}")
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'更新用户信息失败: {str(save_error)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '没有提供任何可更新的字段',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
return Response({
|
||||
'code': 405,
|
||||
'message': f'不支持的请求方法: {request.method}',
|
||||
'data': None
|
||||
}, status=status.HTTP_405_METHOD_NOT_ALLOWED)
|
||||
except Exception as e:
|
||||
logger.error(f"处理用户信息请求失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'处理请求失败: {str(e)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@csrf_exempt
|
||||
@api_view(['POST'])
|
||||
@ -4513,7 +4580,14 @@ def change_password(request):
|
||||
@api_view(['POST'])
|
||||
@permission_classes([AllowAny])
|
||||
def user_register(request):
|
||||
"""用户注册"""
|
||||
"""
|
||||
[已弃用] 用户注册 - 请使用 RegisterView 类代替
|
||||
|
||||
此函数仅保留用于兼容性目的,新代码应该使用 /api/auth/register/ 接口
|
||||
"""
|
||||
# 打印弃用警告
|
||||
logger.warning("使用已弃用的user_register函数,请改用RegisterView类")
|
||||
|
||||
try:
|
||||
data = request.data
|
||||
|
||||
@ -4522,38 +4596,50 @@ def user_register(request):
|
||||
for field in required_fields:
|
||||
if not data.get(field):
|
||||
return Response({
|
||||
'error': f'缺少必填字段: {field}'
|
||||
'code': 400,
|
||||
'message': f'缺少必填字段: {field}',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证角色
|
||||
valid_roles = ['admin', 'leader', 'member']
|
||||
if data['role'] not in valid_roles:
|
||||
return Response({
|
||||
'error': f'无效的角色,必须是: {", ".join(valid_roles)}'
|
||||
'code': 400,
|
||||
'message': f'无效的角色,必须是: {", ".join(valid_roles)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 如果是组员,必须指定小组
|
||||
if data['role'] == 'member' and not data.get('group'):
|
||||
return Response({
|
||||
'error': '组员必须指定所属小组'
|
||||
'code': 400,
|
||||
'message': '组员必须指定所属小组',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 检查用户名是否已存在
|
||||
if User.objects.filter(username=data['username']).exists():
|
||||
return Response({
|
||||
'error': '用户名已存在'
|
||||
'code': 400,
|
||||
'message': '用户名已存在',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 检查邮箱是否已存在
|
||||
if User.objects.filter(email=data['email']).exists():
|
||||
return Response({
|
||||
'error': '邮箱已被注册'
|
||||
'code': 400,
|
||||
'message': '邮箱已被注册',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证密码强度
|
||||
if len(data['password']) < 8:
|
||||
return Response({
|
||||
'error': '密码长度必须至少为8位'
|
||||
'code': 400,
|
||||
'message': '密码长度必须至少为8位',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证邮箱格式
|
||||
@ -4561,7 +4647,9 @@ def user_register(request):
|
||||
validate_email(data['email'])
|
||||
except ValidationError:
|
||||
return Response({
|
||||
'error': '邮箱格式不正确'
|
||||
'code': 400,
|
||||
'message': '邮箱格式不正确',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 创建用户
|
||||
@ -4581,9 +4669,10 @@ def user_register(request):
|
||||
token, _ = Token.objects.get_or_create(user=user)
|
||||
|
||||
return Response({
|
||||
'code': 200,
|
||||
'message': '注册成功',
|
||||
'data': {
|
||||
'id': user.id,
|
||||
'id': str(user.id),
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'role': user.role,
|
||||
@ -4596,82 +4685,41 @@ def user_register(request):
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
|
||||
except Exception as e:
|
||||
print(f"注册失败: {str(e)}")
|
||||
print(f"错误类型: {type(e)}")
|
||||
print(f"错误堆栈: {traceback.format_exc()}")
|
||||
logger.error(f"注册失败: {str(e)}")
|
||||
logger.error(f"错误类型: {type(e)}")
|
||||
logger.error(f"错误堆栈: {traceback.format_exc()}")
|
||||
return Response({
|
||||
'error': f'注册失败: {str(e)}',
|
||||
'code': 500,
|
||||
'message': f'注册失败: {str(e)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@csrf_exempt
|
||||
@api_view(['POST'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def verify_token(request):
|
||||
"""验证令牌有效性"""
|
||||
try:
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "令牌有效",
|
||||
"data": {
|
||||
"is_valid": True,
|
||||
"user": {
|
||||
"id": request.user.id,
|
||||
"username": request.user.username,
|
||||
"email": request.user.email,
|
||||
"role": request.user.role,
|
||||
"department": request.user.department,
|
||||
"name": request.user.name,
|
||||
"group": request.user.group
|
||||
}
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
return Response({
|
||||
"code": 500,
|
||||
"message": f"验证失败: {str(e)}",
|
||||
"data": None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def user_list(request):
|
||||
"""获取用户列表"""
|
||||
user = request.user
|
||||
if user.role == 'admin':
|
||||
users = User.objects.all()
|
||||
elif user.role == 'leader':
|
||||
users = User.objects.filter(department=user.department)
|
||||
else:
|
||||
users = User.objects.filter(id=user.id)
|
||||
|
||||
data = [{
|
||||
'id': u.id,
|
||||
'username': u.username,
|
||||
'email': u.email,
|
||||
'role': u.role,
|
||||
'department': u.department,
|
||||
'is_active': u.is_active,
|
||||
'date_joined': u.date_joined
|
||||
} for u in users]
|
||||
|
||||
return Response(data)
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def user_detail(request, pk):
|
||||
"""获取用户详情"""
|
||||
try:
|
||||
# 尝试转换为 UUID
|
||||
if not isinstance(pk, uuid.UUID):
|
||||
try:
|
||||
pk = uuid.UUID(pk)
|
||||
except ValueError:
|
||||
return Response({
|
||||
"code": 400,
|
||||
"message": "无效的用户ID格式",
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
# 尝试转换为 UUID,处理多种可能的格式
|
||||
try:
|
||||
if not isinstance(pk, uuid.UUID):
|
||||
# 移除所有空格,以防万一
|
||||
pk = pk.strip()
|
||||
|
||||
# 处理带连字符和不带连字符的格式
|
||||
if '-' not in pk and len(pk) == 32:
|
||||
# 转换没有连字符的UUID格式
|
||||
pk_with_hyphens = f"{pk[0:8]}-{pk[8:12]}-{pk[12:16]}-{pk[16:20]}-{pk[20:]}"
|
||||
pk = uuid.UUID(pk_with_hyphens)
|
||||
else:
|
||||
# 尝试直接转换
|
||||
pk = uuid.UUID(pk)
|
||||
except ValueError:
|
||||
# 提供更详细的错误信息
|
||||
return Response({
|
||||
"code": 400,
|
||||
"message": f"无效的用户ID格式: {pk}。用户ID应为有效的UUID格式。",
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
|
||||
@ -4689,6 +4737,8 @@ def user_detail(request, pk):
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"获取用户信息失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return Response({
|
||||
"code": 500,
|
||||
"message": f"获取用户信息失败: {str(e)}",
|
||||
@ -4698,27 +4748,270 @@ def user_detail(request, pk):
|
||||
@api_view(['PUT'])
|
||||
@permission_classes([IsAdminUser])
|
||||
def user_update(request, pk):
|
||||
"""更新用户信息"""
|
||||
"""
|
||||
管理员更新用户信息
|
||||
|
||||
此接口与user_profile的区别:
|
||||
1. 仅管理员可访问
|
||||
2. 可以更新任何用户的信息
|
||||
3. 可以修改角色等重要字段
|
||||
4. 需要在URL中指定用户ID
|
||||
"""
|
||||
try:
|
||||
user = User.objects.get(pk=pk)
|
||||
# 检查请求数据格式
|
||||
try:
|
||||
if not request.data:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '请求数据为空或格式错误',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
except Exception as data_error:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': f'请求数据格式错误: {str(data_error)}。请确保提交的是有效的JSON格式数据,属性名必须使用双引号。',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 尝试转换为 UUID
|
||||
try:
|
||||
if not isinstance(pk, uuid.UUID):
|
||||
pk = pk.strip()
|
||||
|
||||
# 处理带连字符和不带连字符的格式
|
||||
if '-' not in pk and len(pk) == 32:
|
||||
# 转换没有连字符的UUID格式
|
||||
pk_with_hyphens = f"{pk[0:8]}-{pk[8:12]}-{pk[12:16]}-{pk[16:20]}-{pk[20:]}"
|
||||
pk = uuid.UUID(pk_with_hyphens)
|
||||
else:
|
||||
# 尝试直接转换
|
||||
pk = uuid.UUID(pk)
|
||||
except ValueError:
|
||||
return Response({
|
||||
"code": 400,
|
||||
"message": f"无效的用户ID格式: {pk}。用户ID应为有效的UUID格式。",
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
try:
|
||||
user = User.objects.get(pk=pk)
|
||||
except User.DoesNotExist:
|
||||
return Response({
|
||||
'code': 404,
|
||||
'message': '用户不存在',
|
||||
'data': None
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 只允许更新特定字段
|
||||
allowed_fields = ['email', 'role', 'department', 'is_active', 'phone']
|
||||
allowed_fields = ['email', 'role', 'department', 'group', 'is_active', 'phone', 'name']
|
||||
updated_fields = []
|
||||
|
||||
for field in allowed_fields:
|
||||
if field in request.data:
|
||||
setattr(user, field, request.data[field])
|
||||
updated_fields.append(field)
|
||||
|
||||
if not updated_fields:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '没有提供任何可更新的字段',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
user.save()
|
||||
return Response({'message': '用户信息更新成功'})
|
||||
except User.DoesNotExist:
|
||||
return Response({'message': '用户不存在'}, status=404)
|
||||
|
||||
return Response({
|
||||
'code': 200,
|
||||
'message': '用户信息更新成功',
|
||||
'data': {
|
||||
'id': str(user.id),
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'name': user.name,
|
||||
'role': user.role,
|
||||
'department': user.department,
|
||||
'group': user.group,
|
||||
'is_active': user.is_active
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"更新用户信息失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'更新用户信息失败: {str(e)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@api_view(['DELETE'])
|
||||
@permission_classes([IsAdminUser])
|
||||
def user_delete(request, pk):
|
||||
"""删除用户"""
|
||||
try:
|
||||
user = User.objects.get(pk=pk)
|
||||
# 尝试转换为 UUID
|
||||
try:
|
||||
if not isinstance(pk, uuid.UUID):
|
||||
pk = pk.strip()
|
||||
|
||||
# 处理带连字符和不带连字符的格式
|
||||
if '-' not in pk and len(pk) == 32:
|
||||
# 转换没有连字符的UUID格式
|
||||
pk_with_hyphens = f"{pk[0:8]}-{pk[8:12]}-{pk[12:16]}-{pk[16:20]}-{pk[20:]}"
|
||||
pk = uuid.UUID(pk_with_hyphens)
|
||||
else:
|
||||
# 尝试直接转换
|
||||
pk = uuid.UUID(pk)
|
||||
except ValueError:
|
||||
return Response({
|
||||
"code": 400,
|
||||
"message": f"无效的用户ID格式: {pk}。用户ID应为有效的UUID格式。",
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
try:
|
||||
user = User.objects.get(pk=pk)
|
||||
except User.DoesNotExist:
|
||||
return Response({
|
||||
'code': 404,
|
||||
'message': '用户不存在',
|
||||
'data': None
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 检查是否试图删除管理员账户
|
||||
if user.is_superuser or user.role == 'admin':
|
||||
return Response({
|
||||
'code': 403,
|
||||
'message': '不允许删除管理员账户',
|
||||
'data': None
|
||||
}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# 删除用户
|
||||
username = user.username
|
||||
user.delete()
|
||||
return Response({'message': '用户删除成功'})
|
||||
except User.DoesNotExist:
|
||||
return Response({'message': '用户不存在'}, status=404)
|
||||
|
||||
return Response({
|
||||
'code': 200,
|
||||
'message': f'用户 {username} 删除成功',
|
||||
'data': None
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"删除用户失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'删除用户失败: {str(e)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@csrf_exempt
|
||||
@api_view(['POST'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def verify_token(request):
|
||||
"""验证令牌有效性"""
|
||||
try:
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "令牌有效",
|
||||
"data": {
|
||||
"is_valid": True,
|
||||
"user": {
|
||||
"id": str(request.user.id),
|
||||
"username": request.user.username,
|
||||
"email": request.user.email,
|
||||
"name": request.user.name,
|
||||
"role": request.user.role,
|
||||
"department": request.user.department,
|
||||
"group": request.user.group
|
||||
}
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"验证令牌失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return Response({
|
||||
"code": 500,
|
||||
"message": f"验证失败: {str(e)}",
|
||||
"data": None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def user_list(request):
|
||||
"""获取用户列表"""
|
||||
try:
|
||||
# 获取查询参数
|
||||
page = int(request.query_params.get('page', 1))
|
||||
page_size = int(request.query_params.get('page_size', 20))
|
||||
keyword = request.query_params.get('keyword', '')
|
||||
|
||||
# 根据用户角色获取不同范围的用户列表
|
||||
user = request.user
|
||||
base_query = User.objects.all()
|
||||
|
||||
if user.role == 'admin':
|
||||
users_query = base_query
|
||||
elif user.role == 'leader':
|
||||
users_query = base_query.filter(department=user.department)
|
||||
else:
|
||||
users_query = base_query.filter(id=user.id)
|
||||
|
||||
# 添加关键字搜索
|
||||
if keyword:
|
||||
users_query = users_query.filter(
|
||||
Q(username__icontains=keyword) |
|
||||
Q(email__icontains=keyword) |
|
||||
Q(name__icontains=keyword) |
|
||||
Q(department__icontains=keyword)
|
||||
)
|
||||
|
||||
# 计算总数
|
||||
total = users_query.count()
|
||||
|
||||
# 分页
|
||||
start = (page - 1) * page_size
|
||||
end = start + page_size
|
||||
users = users_query[start:end]
|
||||
|
||||
# 构造数据
|
||||
user_data = []
|
||||
for u in users:
|
||||
user_data.append({
|
||||
'id': str(u.id),
|
||||
'username': u.username,
|
||||
'email': u.email,
|
||||
'name': u.name,
|
||||
'role': u.role,
|
||||
'department': u.department,
|
||||
'group': u.group,
|
||||
'is_active': u.is_active,
|
||||
'date_joined': u.date_joined.strftime('%Y-%m-%d %H:%M:%S')
|
||||
})
|
||||
|
||||
return Response({
|
||||
'code': 200,
|
||||
'message': '获取用户列表成功',
|
||||
'data': {
|
||||
'total': total,
|
||||
'page': page,
|
||||
'page_size': page_size,
|
||||
'users': user_data
|
||||
}
|
||||
})
|
||||
|
||||
except ValueError as e:
|
||||
# 处理参数转换错误
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': f'参数错误: {str(e)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取用户列表失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'获取用户列表失败: {str(e)}',
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user