154 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
智能体模块视图 - App端
"""
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from drf_spectacular.utils import extend_schema
from utils.response import success, error
from utils.exceptions import ErrorCode
from apps.admins.authentication import AppJWTAuthentication
from apps.devices.models import UserDevice
from .models import Spirit
from .serializers import (
SpiritSerializer,
SpiritListSerializer,
CreateSpiritSerializer,
)
@extend_schema(tags=['智能体'])
class SpiritViewSet(viewsets.ModelViewSet):
"""智能体视图集App端"""
authentication_classes = [AppJWTAuthentication]
permission_classes = [IsAuthenticated]
def get_queryset(self):
return Spirit.objects.filter(user=self.request.user)
def get_serializer_class(self):
if self.action == 'list':
return SpiritListSerializer
if self.action == 'create':
return CreateSpiritSerializer
return SpiritSerializer
def list(self, request, *args, **kwargs):
"""
获取我的智能体列表
GET /api/v1/spirits
"""
queryset = self.get_queryset()
serializer = SpiritListSerializer(queryset, many=True)
return success(data=serializer.data)
def create(self, request, *args, **kwargs):
"""
创建智能体
POST /api/v1/spirits
"""
serializer = CreateSpiritSerializer(data=request.data)
if serializer.is_valid():
spirit = serializer.save(user=request.user)
return success(data=SpiritSerializer(spirit).data, message='创建成功')
return error(message=str(serializer.errors))
def retrieve(self, request, *args, **kwargs):
"""
获取智能体详情
GET /api/v1/spirits/{id}
"""
try:
instance = self.get_object()
serializer = SpiritSerializer(instance)
return success(data=serializer.data)
except Spirit.DoesNotExist:
return error(code=ErrorCode.SPIRIT_NOT_FOUND, message='智能体不存在')
def update(self, request, *args, **kwargs):
"""
更新智能体
PUT /api/v1/spirits/{id}
"""
instance = self.get_object()
serializer = SpiritSerializer(instance, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return success(data=serializer.data, message='更新成功')
return error(message=str(serializer.errors))
def destroy(self, request, *args, **kwargs):
"""
删除智能体
DELETE /api/v1/spirits/{id}
"""
instance = self.get_object()
instance.delete()
return success(message='删除成功')
@action(detail=True, methods=['post'])
def unbind(self, request, pk=None):
"""
解绑智能体(从所有设备上移除)
POST /api/v1/spirits/{id}/unbind/
"""
try:
spirit = Spirit.objects.get(id=pk, user=request.user)
except Spirit.DoesNotExist:
return error(code=ErrorCode.SPIRIT_NOT_FOUND, message='智能体不存在')
# 解除所有设备与该智能体的绑定
count = UserDevice.objects.filter(
user=request.user, spirit=spirit, is_active=True
).update(spirit=None)
return success(message=f'已解绑智能体,数据已保留在云端(影响 {count} 个设备)')
@action(detail=True, methods=['get'], url_path='owner-info')
def owner_info(self, request, pk=None):
"""
获取智能体所有者信息
GET /api/v1/spirits/{id}/owner-info/
Bug #45 fix: spirit.user (owner) may be None if the user record was
removed outside of the normal cascade path; guard with an explicit
None-check instead of accessing .nickname unconditionally.
"""
try:
spirit = Spirit.objects.get(id=pk, user=request.user)
except Spirit.DoesNotExist:
return error(code=ErrorCode.SPIRIT_NOT_FOUND, message='智能体不存在')
# Bug #45 fix: null-safe access avoid TypeError when owner is None
owner_name = spirit.user.nickname if spirit.user else None
return success(data={'owner_name': owner_name})
@action(detail=True, methods=['post'])
def inject(self, request, pk=None):
"""
注入智能体到设备
POST /api/v1/spirits/{id}/inject/
"""
try:
spirit = Spirit.objects.get(id=pk, user=request.user)
except Spirit.DoesNotExist:
return error(code=ErrorCode.SPIRIT_NOT_FOUND, message='智能体不存在')
user_device_id = request.data.get('user_device_id')
if not user_device_id:
return error(message='请指定设备')
try:
user_device = UserDevice.objects.get(
id=user_device_id, user=request.user, is_active=True
)
except UserDevice.DoesNotExist:
return error(code=ErrorCode.DEVICE_NOT_FOUND, message='设备绑定记录不存在')
user_device.spirit = spirit
user_device.save(update_fields=['spirit'])
return success(message='智能体注入成功')