154 lines
5.3 KiB
Python
154 lines
5.3 KiB
Python
"""
|
||
智能体模块视图 - 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='智能体注入成功')
|