修改token
This commit is contained in:
parent
5f984935cb
commit
e5dae177ef
88
operation/migrations/0001_initial.py
Normal file
88
operation/migrations/0001_initial.py
Normal file
@ -0,0 +1,88 @@
|
||||
# Generated by Django 5.1.5 on 2025-05-14 06:49
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='OperatorAccount',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')),
|
||||
('username', models.CharField(max_length=100, unique=True, verbose_name='用户名')),
|
||||
('password', models.CharField(max_length=255, verbose_name='密码')),
|
||||
('real_name', models.CharField(max_length=50, verbose_name='真实姓名')),
|
||||
('email', models.EmailField(max_length=254, verbose_name='邮箱')),
|
||||
('phone', models.CharField(max_length=15, verbose_name='电话')),
|
||||
('position', models.CharField(choices=[('editor', '编辑'), ('planner', '策划'), ('operator', '运营'), ('admin', '管理员')], max_length=20, verbose_name='工作定位')),
|
||||
('department', models.CharField(max_length=50, verbose_name='部门')),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='是否在职')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '运营账号',
|
||||
'verbose_name_plural': '运营账号',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PlatformAccount',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('platform_name', models.CharField(choices=[('youtube', 'YouTube'), ('tiktok', 'TikTok'), ('twitter', 'Twitter/X'), ('instagram', 'Instagram'), ('facebook', 'Facebook'), ('bilibili', 'Bilibili')], max_length=20, verbose_name='平台名称')),
|
||||
('account_name', models.CharField(max_length=100, verbose_name='账号名称')),
|
||||
('account_id', models.CharField(max_length=100, verbose_name='账号ID')),
|
||||
('status', models.CharField(choices=[('active', '正常'), ('restricted', '限流'), ('suspended', '封禁'), ('inactive', '未激活')], default='active', max_length=20, verbose_name='账号状态')),
|
||||
('followers_count', models.IntegerField(default=0, verbose_name='粉丝数')),
|
||||
('account_url', models.URLField(blank=True, null=True, verbose_name='账号链接')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='账号描述')),
|
||||
('tags', models.CharField(blank=True, help_text='用逗号分隔的标签列表', max_length=255, null=True, verbose_name='标签')),
|
||||
('profile_image', models.URLField(blank=True, null=True, verbose_name='账号头像')),
|
||||
('last_posting', models.DateTimeField(blank=True, null=True, verbose_name='最后发布时间')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='最后登录时间')),
|
||||
('operator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='platform_accounts', to='operation.operatoraccount', verbose_name='关联运营')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '平台账号',
|
||||
'verbose_name_plural': '平台账号',
|
||||
'unique_together': {('platform_name', 'account_id')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Video',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=200, verbose_name='视频标题')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='视频描述')),
|
||||
('video_url', models.URLField(blank=True, null=True, verbose_name='视频地址')),
|
||||
('local_path', models.CharField(blank=True, max_length=255, null=True, verbose_name='本地路径')),
|
||||
('thumbnail_url', models.URLField(blank=True, null=True, verbose_name='缩略图地址')),
|
||||
('status', models.CharField(choices=[('draft', '草稿'), ('scheduled', '已排期'), ('published', '已发布'), ('failed', '发布失败'), ('deleted', '已删除')], default='draft', max_length=20, verbose_name='发布状态')),
|
||||
('views_count', models.IntegerField(default=0, verbose_name='播放次数')),
|
||||
('likes_count', models.IntegerField(default=0, verbose_name='点赞数')),
|
||||
('comments_count', models.IntegerField(default=0, verbose_name='评论数')),
|
||||
('shares_count', models.IntegerField(default=0, verbose_name='分享数')),
|
||||
('tags', models.CharField(blank=True, max_length=500, null=True, verbose_name='标签')),
|
||||
('publish_time', models.DateTimeField(blank=True, null=True, verbose_name='发布时间')),
|
||||
('video_id', models.CharField(blank=True, max_length=100, null=True, verbose_name='视频ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('platform_account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='videos', to='operation.platformaccount', verbose_name='发布账号')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '视频',
|
||||
'verbose_name_plural': '视频',
|
||||
},
|
||||
),
|
||||
]
|
@ -1,6 +1,118 @@
|
||||
from django.db import models
|
||||
from user_management.models import OperatorAccount, PlatformAccount, Video, KnowledgeBase, KnowledgeBaseDocument
|
||||
import uuid
|
||||
from django.utils import timezone
|
||||
|
||||
# Create your models here.
|
||||
|
||||
# 我们可以在这里添加额外的模型或关系,但现在使用user_management中的现有模型
|
||||
|
||||
class OperatorAccount(models.Model):
|
||||
"""运营账号信息表"""
|
||||
|
||||
id = models.AutoField(primary_key=True)
|
||||
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='UUID')
|
||||
|
||||
POSITION_CHOICES = [
|
||||
('editor', '编辑'),
|
||||
('planner', '策划'),
|
||||
('operator', '运营'),
|
||||
('admin', '管理员'),
|
||||
]
|
||||
|
||||
username = models.CharField(max_length=100, unique=True, verbose_name='用户名')
|
||||
password = models.CharField(max_length=255, verbose_name='密码')
|
||||
real_name = models.CharField(max_length=50, verbose_name='真实姓名')
|
||||
email = models.EmailField(verbose_name='邮箱')
|
||||
phone = models.CharField(max_length=15, verbose_name='电话')
|
||||
position = models.CharField(max_length=20, choices=POSITION_CHOICES, verbose_name='工作定位')
|
||||
department = models.CharField(max_length=50, verbose_name='部门')
|
||||
is_active = models.BooleanField(default=True, verbose_name='是否在职')
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '运营账号'
|
||||
verbose_name_plural = '运营账号'
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.real_name} ({self.username})"
|
||||
|
||||
class PlatformAccount(models.Model):
|
||||
"""平台账号信息表"""
|
||||
|
||||
STATUS_CHOICES = [
|
||||
('active', '正常'),
|
||||
('restricted', '限流'),
|
||||
('suspended', '封禁'),
|
||||
('inactive', '未激活'),
|
||||
]
|
||||
|
||||
PLATFORM_CHOICES = [
|
||||
('youtube', 'YouTube'),
|
||||
('tiktok', 'TikTok'),
|
||||
('twitter', 'Twitter/X'),
|
||||
('instagram', 'Instagram'),
|
||||
('facebook', 'Facebook'),
|
||||
('bilibili', 'Bilibili'),
|
||||
]
|
||||
|
||||
operator = models.ForeignKey(OperatorAccount, on_delete=models.CASCADE, related_name='platform_accounts', verbose_name='关联运营')
|
||||
platform_name = models.CharField(max_length=20, choices=PLATFORM_CHOICES, verbose_name='平台名称')
|
||||
account_name = models.CharField(max_length=100, verbose_name='账号名称')
|
||||
account_id = models.CharField(max_length=100, verbose_name='账号ID')
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active', verbose_name='账号状态')
|
||||
followers_count = models.IntegerField(default=0, verbose_name='粉丝数')
|
||||
account_url = models.URLField(blank=True, null=True, verbose_name='账号链接')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='账号描述')
|
||||
|
||||
# 新增字段
|
||||
tags = models.CharField(max_length=255, blank=True, null=True, verbose_name='标签', help_text='用逗号分隔的标签列表')
|
||||
profile_image = models.URLField(blank=True, null=True, verbose_name='账号头像')
|
||||
last_posting = models.DateTimeField(blank=True, null=True, verbose_name='最后发布时间')
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
last_login = models.DateTimeField(blank=True, null=True, verbose_name='最后登录时间')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '平台账号'
|
||||
verbose_name_plural = '平台账号'
|
||||
unique_together = ('platform_name', 'account_id')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.account_name} ({self.get_platform_name_display()})"
|
||||
|
||||
class Video(models.Model):
|
||||
"""视频信息表"""
|
||||
|
||||
STATUS_CHOICES = [
|
||||
('draft', '草稿'),
|
||||
('scheduled', '已排期'),
|
||||
('published', '已发布'),
|
||||
('failed', '发布失败'),
|
||||
('deleted', '已删除'),
|
||||
]
|
||||
|
||||
platform_account = models.ForeignKey(PlatformAccount, on_delete=models.CASCADE, related_name='videos', verbose_name='发布账号')
|
||||
title = models.CharField(max_length=200, verbose_name='视频标题')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='视频描述')
|
||||
video_url = models.URLField(blank=True, null=True, verbose_name='视频地址')
|
||||
local_path = models.CharField(max_length=255, blank=True, null=True, verbose_name='本地路径')
|
||||
thumbnail_url = models.URLField(blank=True, null=True, verbose_name='缩略图地址')
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft', verbose_name='发布状态')
|
||||
views_count = models.IntegerField(default=0, verbose_name='播放次数')
|
||||
likes_count = models.IntegerField(default=0, verbose_name='点赞数')
|
||||
comments_count = models.IntegerField(default=0, verbose_name='评论数')
|
||||
shares_count = models.IntegerField(default=0, verbose_name='分享数')
|
||||
tags = models.CharField(max_length=500, blank=True, null=True, verbose_name='标签')
|
||||
publish_time = models.DateTimeField(blank=True, null=True, verbose_name='发布时间')
|
||||
video_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='视频ID')
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '视频'
|
||||
verbose_name_plural = '视频'
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title} ({self.platform_account.account_name})"
|
||||
|
@ -1,32 +1,20 @@
|
||||
from rest_framework import serializers
|
||||
from user_management.models import OperatorAccount, PlatformAccount, Video, KnowledgeBase, KnowledgeBaseDocument
|
||||
from .models import OperatorAccount, PlatformAccount, Video
|
||||
import uuid
|
||||
from django.db.models import Q
|
||||
|
||||
|
||||
class OperatorAccountSerializer(serializers.ModelSerializer):
|
||||
id = serializers.UUIDField(read_only=False, required=False) # 允许前端不提供ID,但如果提供则必须是有效的UUID
|
||||
id = serializers.IntegerField(read_only=True) # ID是自动递增的整数字段
|
||||
|
||||
class Meta:
|
||||
model = OperatorAccount
|
||||
fields = ['id', 'username', 'password', 'real_name', 'email', 'phone', 'position', 'department', 'is_active', 'created_at', 'updated_at']
|
||||
read_only_fields = ['created_at', 'updated_at']
|
||||
fields = ['id', 'uuid', 'username', 'password', 'real_name', 'email', 'phone', 'position', 'department', 'is_active', 'created_at', 'updated_at']
|
||||
read_only_fields = ['created_at', 'updated_at', 'uuid']
|
||||
extra_kwargs = {
|
||||
'password': {'write_only': True}
|
||||
}
|
||||
|
||||
def create(self, validated_data):
|
||||
# 如果没有提供ID,则生成一个UUID
|
||||
if 'id' not in validated_data:
|
||||
validated_data['id'] = uuid.uuid4()
|
||||
|
||||
password = validated_data.pop('password', None)
|
||||
instance = self.Meta.model(**validated_data)
|
||||
if password:
|
||||
instance.password = password # 在实际应用中应该加密存储密码
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
|
||||
class PlatformAccountSerializer(serializers.ModelSerializer):
|
||||
operator_name = serializers.CharField(source='operator.real_name', read_only=True)
|
||||
@ -40,7 +28,7 @@ class PlatformAccountSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = ['id', 'created_at', 'updated_at']
|
||||
|
||||
def to_internal_value(self, data):
|
||||
# 处理operator字段,可能是字符串格式的UUID
|
||||
# 处理operator字段,可能是字符串格式的ID
|
||||
if 'operator' in data and isinstance(data['operator'], str):
|
||||
try:
|
||||
# 尝试获取对应的运营账号对象
|
||||
@ -129,7 +117,7 @@ class VideoSerializer(serializers.ModelSerializer):
|
||||
fields = ['id', 'platform_account', 'platform_account_name', 'platform_name', 'title',
|
||||
'description', 'video_url', 'local_path', 'thumbnail_url', 'status',
|
||||
'views_count', 'likes_count', 'comments_count', 'shares_count', 'tags',
|
||||
'publish_time', 'scheduled_time', 'created_at', 'updated_at']
|
||||
'publish_time', 'video_id', 'created_at', 'updated_at']
|
||||
read_only_fields = ['id', 'created_at', 'updated_at', 'views_count', 'likes_count',
|
||||
'comments_count', 'shares_count']
|
||||
|
||||
@ -139,7 +127,7 @@ class VideoSerializer(serializers.ModelSerializer):
|
||||
data = data.copy()
|
||||
data['tags'] = ','.join(data['tags'])
|
||||
|
||||
# 处理platform_account字段,可能是字符串格式的UUID
|
||||
# 处理platform_account字段,可能是字符串格式的ID
|
||||
if 'platform_account' in data and isinstance(data['platform_account'], str):
|
||||
try:
|
||||
# 尝试获取对应的平台账号对象
|
||||
@ -161,19 +149,3 @@ class VideoSerializer(serializers.ModelSerializer):
|
||||
representation['tags'] = representation['tags'].split(',')
|
||||
return representation
|
||||
|
||||
|
||||
class KnowledgeBaseSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = KnowledgeBase
|
||||
fields = ['id', 'user_id', 'name', 'desc', 'type', 'department', 'group',
|
||||
'external_id', 'create_time', 'update_time']
|
||||
read_only_fields = ['id', 'create_time', 'update_time']
|
||||
|
||||
|
||||
class KnowledgeBaseDocumentSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = KnowledgeBaseDocument
|
||||
fields = ['id', 'knowledge_base', 'document_id', 'document_name',
|
||||
'external_id', 'uploader_name', 'status', 'create_time', 'update_time']
|
||||
read_only_fields = ['id', 'create_time', 'update_time']
|
||||
|
@ -9,14 +9,13 @@ from django.utils import timezone
|
||||
from rest_framework import viewsets, status
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from django.db.models import Q
|
||||
import os
|
||||
|
||||
from user_management.models import OperatorAccount, PlatformAccount, Video, KnowledgeBase, KnowledgeBaseDocument, User
|
||||
from .models import OperatorAccount, PlatformAccount, Video
|
||||
from .serializers import (
|
||||
OperatorAccountSerializer, PlatformAccountSerializer, VideoSerializer,
|
||||
KnowledgeBaseSerializer, KnowledgeBaseDocumentSerializer, MultiPlatformAccountSerializer
|
||||
MultiPlatformAccountSerializer
|
||||
)
|
||||
from .pagination import CustomPagination
|
||||
|
||||
@ -26,7 +25,6 @@ class OperatorAccountViewSet(viewsets.ModelViewSet):
|
||||
"""运营账号管理视图集"""
|
||||
queryset = OperatorAccount.objects.all()
|
||||
serializer_class = OperatorAccountSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
pagination_class = CustomPagination
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
@ -76,125 +74,34 @@ class OperatorAccountViewSet(viewsets.ModelViewSet):
|
||||
return self.update(request, *args, **kwargs)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""创建运营账号并自动创建对应的私有知识库"""
|
||||
with transaction.atomic():
|
||||
# 1. 创建运营账号
|
||||
"""创建运营账号"""
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# 2. 手动保存数据而不是使用serializer.save(),确保不传入UUID
|
||||
operator_data = serializer.validated_data
|
||||
operator = OperatorAccount.objects.create(**operator_data)
|
||||
|
||||
# 3. 为每个运营账号创建一个私有知识库
|
||||
knowledge_base = KnowledgeBase.objects.create(
|
||||
user_id=request.user.id, # 使用当前用户作为创建者
|
||||
name=f"{operator.real_name}的运营知识库",
|
||||
desc=f"用于存储{operator.real_name}({operator.username})相关的运营数据",
|
||||
type='private',
|
||||
department=operator.department
|
||||
)
|
||||
|
||||
# 4. 创建知识库文档记录 - 运营信息文档
|
||||
document_data = {
|
||||
"name": f"{operator.real_name}_运营信息",
|
||||
"paragraphs": [
|
||||
{
|
||||
"title": "运营账号基本信息",
|
||||
"content": f"""
|
||||
用户名: {operator.username}
|
||||
真实姓名: {operator.real_name}
|
||||
邮箱: {operator.email}
|
||||
电话: {operator.phone}
|
||||
职位: {operator.get_position_display()}
|
||||
部门: {operator.department}
|
||||
创建时间: {operator.created_at.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
uuid: {operator.uuid}
|
||||
""",
|
||||
"is_active": True
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 调用外部API创建文档
|
||||
document_id = self._create_document(knowledge_base.external_id, document_data)
|
||||
|
||||
if document_id:
|
||||
# 创建知识库文档记录
|
||||
KnowledgeBaseDocument.objects.create(
|
||||
knowledge_base=knowledge_base,
|
||||
document_id=document_id,
|
||||
document_name=document_data["name"],
|
||||
external_id=document_id,
|
||||
uploader_name=request.user.username
|
||||
)
|
||||
self.perform_create(serializer)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "运营账号创建成功,并已创建对应知识库",
|
||||
"data": {
|
||||
"operator": self.get_serializer(operator).data,
|
||||
"knowledge_base": {
|
||||
"id": knowledge_base.id,
|
||||
"name": knowledge_base.name,
|
||||
"external_id": knowledge_base.external_id
|
||||
}
|
||||
}
|
||||
"message": "运营账号创建成功",
|
||||
"data": serializer.data
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
"""删除运营账号并更新相关知识库状态"""
|
||||
"""删除运营账号"""
|
||||
operator = self.get_object()
|
||||
|
||||
# 更新知识库状态或删除关联文档
|
||||
knowledge_bases = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
)
|
||||
|
||||
for kb in knowledge_bases:
|
||||
# 可以选择删除知识库,或者更新知识库状态
|
||||
# 这里我们更新对应的文档状态
|
||||
documents = KnowledgeBaseDocument.objects.filter(
|
||||
knowledge_base=kb,
|
||||
document_name__contains=operator.real_name
|
||||
)
|
||||
|
||||
for doc in documents:
|
||||
doc.status = 'deleted'
|
||||
doc.save()
|
||||
|
||||
operator.is_active = False # 软删除
|
||||
operator.save()
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "运营账号已停用,相关知识库文档已标记为删除",
|
||||
"message": "运营账号已停用",
|
||||
"data": None
|
||||
})
|
||||
|
||||
def _create_document(self, external_id, doc_data):
|
||||
"""调用外部API创建文档"""
|
||||
try:
|
||||
if not external_id:
|
||||
logger.error("创建文档失败:知识库external_id为空")
|
||||
return None
|
||||
|
||||
# 在实际应用中,这里需要调用外部API创建文档
|
||||
# 模拟创建文档并返回document_id
|
||||
document_id = str(uuid.uuid4())
|
||||
logger.info(f"模拟创建文档成功,document_id: {document_id}")
|
||||
return document_id
|
||||
except Exception as e:
|
||||
logger.error(f"创建文档失败: {str(e)}")
|
||||
return None
|
||||
|
||||
|
||||
class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
"""平台账号管理视图集"""
|
||||
queryset = PlatformAccount.objects.all()
|
||||
serializer_class = PlatformAccountSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
pagination_class = CustomPagination
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
@ -204,24 +111,60 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
|
||||
if page is not None:
|
||||
serializer = self.get_serializer(page, many=True)
|
||||
# 使用自定义分页器的响应
|
||||
return self.get_paginated_response(serializer.data)
|
||||
# 处理数据结构
|
||||
response_data = serializer.data
|
||||
restructured_data = []
|
||||
for account_data in response_data:
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url")
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = platform_info
|
||||
restructured_data.append(account_data)
|
||||
|
||||
# 使用自定义分页器的响应,但替换数据
|
||||
return self.get_paginated_response(restructured_data)
|
||||
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
# 处理数据结构
|
||||
response_data = serializer.data
|
||||
restructured_data = []
|
||||
for account_data in response_data:
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url")
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = platform_info
|
||||
restructured_data.append(account_data)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "获取平台账号列表成功",
|
||||
"data": serializer.data
|
||||
"data": restructured_data
|
||||
})
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
"""获取平台账号详情"""
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(instance)
|
||||
# 处理数据结构
|
||||
account_data = serializer.data
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url")
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = platform_info
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "获取平台账号详情成功",
|
||||
"data": serializer.data
|
||||
"data": account_data
|
||||
})
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
@ -232,10 +175,20 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_update(serializer)
|
||||
|
||||
# 处理数据结构
|
||||
account_data = serializer.data
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url")
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = platform_info
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "更新平台账号信息成功",
|
||||
"data": serializer.data
|
||||
"data": account_data
|
||||
})
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
@ -244,7 +197,7 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
return self.update(request, *args, **kwargs)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""创建平台账号并记录到知识库"""
|
||||
"""创建平台账号"""
|
||||
# 检查请求数据中是否包含platforms字段,判断是否为多平台账号创建
|
||||
if 'platforms' in request.data and isinstance(request.data['platforms'], list):
|
||||
# 使用多平台账号序列化器
|
||||
@ -270,15 +223,28 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
platform_account = PlatformAccount.objects.create(**platform_account_data)
|
||||
created_accounts.append(platform_account)
|
||||
|
||||
# 记录到知识库
|
||||
self._add_to_knowledge_base(platform_account, request.user)
|
||||
|
||||
# 将创建的账号序列化返回
|
||||
result_serializer = self.get_serializer(created_accounts, many=True)
|
||||
# 修改响应数据结构
|
||||
response_data = result_serializer.data
|
||||
|
||||
# 重新组织数据格式
|
||||
restructured_data = []
|
||||
for account_data in response_data:
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url")
|
||||
}
|
||||
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = platform_info
|
||||
restructured_data.append(account_data)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "多平台账号创建成功,并已添加到知识库",
|
||||
"data": result_serializer.data
|
||||
"message": "多平台账号创建成功",
|
||||
"data": restructured_data
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
else:
|
||||
# 传统单平台账号创建流程
|
||||
@ -320,123 +286,39 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
serializer = self.get_serializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# 手动创建平台账号,不使用serializer.save()避免ID问题
|
||||
platform_data = serializer.validated_data
|
||||
platform_account = PlatformAccount.objects.create(**platform_data)
|
||||
# 创建平台账号
|
||||
self.perform_create(serializer)
|
||||
|
||||
# 记录到知识库
|
||||
self._add_to_knowledge_base(platform_account, request.user)
|
||||
# 处理响应数据
|
||||
account_data = serializer.data
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": account_data.pop("platform_name"),
|
||||
"account_url": account_data.pop("account_url")
|
||||
}
|
||||
# 添加platforms字段
|
||||
account_data["platforms"] = platform_info
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "平台账号创建成功,并已添加到知识库",
|
||||
"data": self.get_serializer(platform_account).data
|
||||
"message": "平台账号创建成功",
|
||||
"data": account_data
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
|
||||
def _add_to_knowledge_base(self, platform_account, user):
|
||||
"""将平台账号添加到知识库"""
|
||||
# 获取关联的运营账号
|
||||
operator = platform_account.operator
|
||||
|
||||
# 查找对应的知识库
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base and knowledge_base.external_id:
|
||||
# 创建平台账号文档
|
||||
document_data = {
|
||||
"name": f"{platform_account.account_name}_{platform_account.platform_name}_账号信息",
|
||||
"paragraphs": [
|
||||
{
|
||||
"title": "平台账号基本信息",
|
||||
"content": f"""
|
||||
平台: {platform_account.get_platform_name_display()}
|
||||
账号名称: {platform_account.account_name}
|
||||
账号ID: {platform_account.account_id}
|
||||
账号状态: {platform_account.get_status_display()}
|
||||
粉丝数: {platform_account.followers_count}
|
||||
账号链接: {platform_account.account_url}
|
||||
账号描述: {platform_account.description or '无'}
|
||||
标签: {platform_account.tags or '无'}
|
||||
头像链接: {platform_account.profile_image or '无'}
|
||||
最后发布时间: {platform_account.last_posting.strftime('%Y-%m-%d %H:%M:%S') if platform_account.last_posting else '未发布'}
|
||||
创建时间: {platform_account.created_at.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
最后登录: {platform_account.last_login.strftime('%Y-%m-%d %H:%M:%S') if platform_account.last_login else '从未登录'}
|
||||
""",
|
||||
"is_active": True
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 调用外部API创建文档
|
||||
document_id = self._create_document(knowledge_base.external_id, document_data)
|
||||
|
||||
if document_id:
|
||||
# 创建知识库文档记录
|
||||
KnowledgeBaseDocument.objects.create(
|
||||
knowledge_base=knowledge_base,
|
||||
document_id=document_id,
|
||||
document_name=document_data["name"],
|
||||
external_id=document_id,
|
||||
uploader_name=user.username
|
||||
)
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
"""删除平台账号并更新相关知识库文档"""
|
||||
"""删除平台账号"""
|
||||
platform_account = self.get_object()
|
||||
|
||||
# 获取关联的运营账号
|
||||
operator = platform_account.operator
|
||||
|
||||
# 查找对应的知识库
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base:
|
||||
# 查找相关文档并标记为删除
|
||||
documents = KnowledgeBaseDocument.objects.filter(
|
||||
knowledge_base=knowledge_base
|
||||
).filter(
|
||||
Q(document_name__contains=platform_account.account_name) |
|
||||
Q(document_name__contains=platform_account.platform_name)
|
||||
)
|
||||
|
||||
for doc in documents:
|
||||
doc.status = 'deleted'
|
||||
doc.save()
|
||||
|
||||
# 删除平台账号
|
||||
self.perform_destroy(platform_account)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "平台账号已删除,相关知识库文档已标记为删除",
|
||||
"message": "平台账号已删除",
|
||||
"data": None
|
||||
})
|
||||
|
||||
def _create_document(self, external_id, doc_data):
|
||||
"""调用外部API创建文档"""
|
||||
try:
|
||||
if not external_id:
|
||||
logger.error("创建文档失败:知识库external_id为空")
|
||||
return None
|
||||
|
||||
# 在实际应用中,这里需要调用外部API创建文档
|
||||
# 模拟创建文档并返回document_id
|
||||
document_id = str(uuid.uuid4())
|
||||
logger.info(f"模拟创建文档成功,document_id: {document_id}")
|
||||
return document_id
|
||||
except Exception as e:
|
||||
logger.error(f"创建文档失败: {str(e)}")
|
||||
return None
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def update_followers(self, request, pk=None):
|
||||
"""更新平台账号粉丝数并同步到知识库"""
|
||||
"""更新平台账号粉丝数"""
|
||||
platform_account = self.get_object()
|
||||
followers_count = request.data.get('followers_count')
|
||||
|
||||
@ -451,36 +333,20 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
platform_account.followers_count = followers_count
|
||||
platform_account.save()
|
||||
|
||||
# 同步到知识库
|
||||
operator = platform_account.operator
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base:
|
||||
# 查找相关文档
|
||||
document = KnowledgeBaseDocument.objects.filter(
|
||||
knowledge_base=knowledge_base,
|
||||
status='active'
|
||||
).filter(
|
||||
Q(document_name__contains=platform_account.account_name) |
|
||||
Q(document_name__contains=platform_account.platform_name)
|
||||
).first()
|
||||
|
||||
if document:
|
||||
# 这里应该调用外部API更新文档内容
|
||||
# 但由于我们没有实际的API,只做记录
|
||||
logger.info(f"应当更新文档 {document.document_id} 的粉丝数为 {followers_count}")
|
||||
# 准备响应数据,与其他方法保持一致
|
||||
platform_data = self.get_serializer(platform_account).data
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": platform_data.pop("platform_name"),
|
||||
"account_url": platform_data.pop("account_url")
|
||||
}
|
||||
# 添加platforms字段
|
||||
platform_data["platforms"] = platform_info
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "粉丝数更新成功",
|
||||
"data": {
|
||||
"id": platform_account.id,
|
||||
"account_name": platform_account.account_name,
|
||||
"followers_count": platform_account.followers_count
|
||||
}
|
||||
"data": platform_data
|
||||
})
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
@ -530,30 +396,20 @@ class PlatformAccountViewSet(viewsets.ModelViewSet):
|
||||
setattr(platform_account, field, value)
|
||||
platform_account.save()
|
||||
|
||||
# 同步到知识库
|
||||
# 在实际应用中应该调用外部API更新文档内容
|
||||
operator = platform_account.operator
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base:
|
||||
document = KnowledgeBaseDocument.objects.filter(
|
||||
knowledge_base=knowledge_base,
|
||||
status='active'
|
||||
).filter(
|
||||
Q(document_name__contains=platform_account.account_name) |
|
||||
Q(document_name__contains=platform_account.platform_name)
|
||||
).first()
|
||||
|
||||
if document:
|
||||
logger.info(f"应当更新文档 {document.document_id} 的平台账号资料数据")
|
||||
# 准备响应数据,与其他方法保持一致
|
||||
platform_data = self.get_serializer(platform_account).data
|
||||
# 提取平台信息并放入platforms字段
|
||||
platform_info = {
|
||||
"platform_name": platform_data.pop("platform_name"),
|
||||
"account_url": platform_data.pop("account_url")
|
||||
}
|
||||
# 添加platforms字段
|
||||
platform_data["platforms"] = platform_info
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "平台账号资料更新成功",
|
||||
"data": self.get_serializer(platform_account).data
|
||||
"data": platform_data
|
||||
})
|
||||
|
||||
|
||||
@ -561,7 +417,6 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
"""视频管理视图集"""
|
||||
queryset = Video.objects.all()
|
||||
serializer_class = VideoSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
pagination_class = CustomPagination
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
@ -611,7 +466,7 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
return self.update(request, *args, **kwargs)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""创建视频并记录到知识库"""
|
||||
"""创建视频"""
|
||||
with transaction.atomic():
|
||||
# 处理platform_account字段,可能是字符串类型的ID
|
||||
data = request.data.copy()
|
||||
@ -650,117 +505,29 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
serializer = self.get_serializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# 手动创建视频,不使用serializer.save()避免ID问题
|
||||
video_data = serializer.validated_data
|
||||
video = Video.objects.create(**video_data)
|
||||
|
||||
# 获取关联的平台账号和运营账号
|
||||
platform_account = video.platform_account
|
||||
operator = platform_account.operator
|
||||
|
||||
# 查找对应的知识库
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base and knowledge_base.external_id:
|
||||
# 创建视频文档
|
||||
document_data = {
|
||||
"name": f"{video.title}_{platform_account.account_name}_视频信息",
|
||||
"paragraphs": [
|
||||
{
|
||||
"title": "视频基本信息",
|
||||
"content": f"""
|
||||
标题: {video.title}
|
||||
平台: {platform_account.get_platform_name_display()}
|
||||
账号: {platform_account.account_name}
|
||||
视频ID: {video.video_id}
|
||||
发布时间: {video.publish_time.strftime('%Y-%m-%d %H:%M:%S') if video.publish_time else '未发布'}
|
||||
视频链接: {video.video_url}
|
||||
点赞数: {video.likes_count}
|
||||
评论数: {video.comments_count}
|
||||
分享数: {video.shares_count}
|
||||
观看数: {video.views_count}
|
||||
视频描述: {video.description or '无'}
|
||||
""",
|
||||
"is_active": True
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 调用外部API创建文档
|
||||
document_id = self._create_document(knowledge_base.external_id, document_data)
|
||||
|
||||
if document_id:
|
||||
# 创建知识库文档记录
|
||||
KnowledgeBaseDocument.objects.create(
|
||||
knowledge_base=knowledge_base,
|
||||
document_id=document_id,
|
||||
document_name=document_data["name"],
|
||||
external_id=document_id,
|
||||
uploader_name=request.user.username
|
||||
)
|
||||
# 创建视频
|
||||
self.perform_create(serializer)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "视频创建成功,并已添加到知识库",
|
||||
"data": self.get_serializer(video).data
|
||||
"message": "视频创建成功",
|
||||
"data": serializer.data
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
"""删除视频记录并更新相关知识库文档"""
|
||||
"""删除视频记录"""
|
||||
video = self.get_object()
|
||||
|
||||
# 获取关联的平台账号和运营账号
|
||||
platform_account = video.platform_account
|
||||
operator = platform_account.operator
|
||||
|
||||
# 查找对应的知识库
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base:
|
||||
# 查找相关文档并标记为删除
|
||||
documents = KnowledgeBaseDocument.objects.filter(
|
||||
knowledge_base=knowledge_base,
|
||||
document_name__contains=video.title
|
||||
)
|
||||
|
||||
for doc in documents:
|
||||
doc.status = 'deleted'
|
||||
doc.save()
|
||||
|
||||
# 删除视频记录
|
||||
self.perform_destroy(video)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "视频记录已删除,相关知识库文档已标记为删除",
|
||||
"message": "视频记录已删除",
|
||||
"data": None
|
||||
})
|
||||
|
||||
def _create_document(self, external_id, doc_data):
|
||||
"""调用外部API创建文档"""
|
||||
try:
|
||||
if not external_id:
|
||||
logger.error("创建文档失败:知识库external_id为空")
|
||||
return None
|
||||
|
||||
# 在实际应用中,这里需要调用外部API创建文档
|
||||
# 模拟创建文档并返回document_id
|
||||
document_id = str(uuid.uuid4())
|
||||
logger.info(f"模拟创建文档成功,document_id: {document_id}")
|
||||
return document_id
|
||||
except Exception as e:
|
||||
logger.error(f"创建文档失败: {str(e)}")
|
||||
return None
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def update_stats(self, request, pk=None):
|
||||
"""更新视频统计数据并同步到知识库"""
|
||||
"""更新视频统计数据"""
|
||||
video = self.get_object()
|
||||
|
||||
# 获取更新的统计数据
|
||||
@ -781,25 +548,6 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
setattr(video, field, value)
|
||||
video.save()
|
||||
|
||||
# 同步到知识库
|
||||
# 在实际应用中应该调用外部API更新文档内容
|
||||
platform_account = video.platform_account
|
||||
operator = platform_account.operator
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base:
|
||||
document = KnowledgeBaseDocument.objects.filter(
|
||||
knowledge_base=knowledge_base,
|
||||
document_name__contains=video.title,
|
||||
status='active'
|
||||
).first()
|
||||
|
||||
if document:
|
||||
logger.info(f"应当更新文档 {document.document_id} 的视频统计数据")
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "视频统计数据更新成功",
|
||||
@ -841,25 +589,6 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
video.publish_time = timezone.now()
|
||||
video.save()
|
||||
|
||||
# 同步到知识库
|
||||
# 在实际应用中应该调用外部API更新文档内容
|
||||
platform_account = video.platform_account
|
||||
operator = platform_account.operator
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base:
|
||||
document = KnowledgeBaseDocument.objects.filter(
|
||||
knowledge_base=knowledge_base,
|
||||
document_name__contains=video.title,
|
||||
status='active'
|
||||
).first()
|
||||
|
||||
if document:
|
||||
logger.info(f"应当更新文档 {document.document_id} 的视频发布状态")
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "视频已成功发布",
|
||||
@ -938,31 +667,9 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
'tags': request.data.get('tags', '')
|
||||
}
|
||||
|
||||
# 如果提供了计划发布时间,则设置状态为已排期
|
||||
scheduled_time = request.data.get('scheduled_time')
|
||||
if scheduled_time:
|
||||
from dateutil import parser
|
||||
try:
|
||||
parsed_time = parser.parse(scheduled_time)
|
||||
video_data['scheduled_time'] = parsed_time
|
||||
video_data['status'] = 'scheduled'
|
||||
except Exception as e:
|
||||
return Response({
|
||||
"code": 400,
|
||||
"message": f"计划发布时间格式错误: {str(e)}",
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 创建视频记录
|
||||
video = Video.objects.create(**video_data)
|
||||
|
||||
# 添加到知识库
|
||||
self._add_to_knowledge_base(video, platform_account)
|
||||
|
||||
# 如果是已排期状态,创建定时任务
|
||||
if video.status == 'scheduled':
|
||||
self._create_publish_task(video)
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "视频上传成功",
|
||||
@ -970,7 +677,6 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
"id": video.id,
|
||||
"title": video.title,
|
||||
"status": video.get_status_display(),
|
||||
"scheduled_time": video.scheduled_time
|
||||
}
|
||||
}, status=status.HTTP_201_CREATED)
|
||||
|
||||
@ -982,87 +688,6 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
"data": None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
def _add_to_knowledge_base(self, video, platform_account):
|
||||
"""将视频添加到知识库"""
|
||||
# 获取关联的运营账号
|
||||
operator = platform_account.operator
|
||||
|
||||
# 查找对应的知识库
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base and knowledge_base.external_id:
|
||||
# 创建视频文档
|
||||
document_data = {
|
||||
"name": f"{video.title}_{platform_account.account_name}_视频信息",
|
||||
"paragraphs": [
|
||||
{
|
||||
"title": "视频基本信息",
|
||||
"content": f"""
|
||||
标题: {video.title}
|
||||
平台: {platform_account.get_platform_name_display()}
|
||||
账号: {platform_account.account_name}
|
||||
状态: {video.get_status_display()}
|
||||
本地路径: {video.local_path}
|
||||
计划发布时间: {video.scheduled_time.strftime('%Y-%m-%d %H:%M:%S') if video.scheduled_time else '未设置'}
|
||||
视频描述: {video.description or '无'}
|
||||
标签: {video.tags or '无'}
|
||||
创建时间: {video.created_at.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
""",
|
||||
"is_active": True
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 调用外部API创建文档
|
||||
document_id = self._create_document(knowledge_base.external_id, document_data)
|
||||
|
||||
if document_id:
|
||||
# 创建知识库文档记录
|
||||
KnowledgeBaseDocument.objects.create(
|
||||
knowledge_base=knowledge_base,
|
||||
document_id=document_id,
|
||||
document_name=document_data["name"],
|
||||
external_id=document_id,
|
||||
uploader_name="系统"
|
||||
)
|
||||
|
||||
def _create_publish_task(self, video):
|
||||
"""创建定时发布任务"""
|
||||
try:
|
||||
from django_celery_beat.models import PeriodicTask, CrontabSchedule
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
scheduled_time = video.scheduled_time
|
||||
|
||||
# 创建定时任务
|
||||
schedule, _ = CrontabSchedule.objects.get_or_create(
|
||||
minute=scheduled_time.minute,
|
||||
hour=scheduled_time.hour,
|
||||
day_of_month=scheduled_time.day,
|
||||
month_of_year=scheduled_time.month,
|
||||
)
|
||||
|
||||
# 创建周期性任务
|
||||
task_name = f"Publish_Video_{video.id}_{datetime.now().timestamp()}"
|
||||
PeriodicTask.objects.create(
|
||||
name=task_name,
|
||||
task='user_management.tasks.publish_scheduled_video',
|
||||
crontab=schedule,
|
||||
args=json.dumps([video.id]),
|
||||
one_off=True, # 只执行一次
|
||||
start_time=scheduled_time
|
||||
)
|
||||
|
||||
logger.info(f"已创建视频 {video.id} 的定时发布任务,计划发布时间: {scheduled_time}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"创建定时发布任务失败: {str(e)}")
|
||||
# 记录错误但不中断流程
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def manual_publish(self, request, pk=None):
|
||||
"""手动发布视频"""
|
||||
@ -1077,51 +702,32 @@ class VideoViewSet(viewsets.ModelViewSet):
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 检查视频文件是否存在
|
||||
if not video.local_path or not os.path.exists(video.local_path):
|
||||
if video.local_path and not os.path.exists(video.local_path):
|
||||
return Response({
|
||||
"code": 400,
|
||||
"message": "视频文件不存在,无法发布",
|
||||
"data": None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 自动发布 - 不依赖Celery任务
|
||||
try:
|
||||
# 模拟上传到平台
|
||||
# 获取视频URL,如果没有提供,则创建一个模拟的URL
|
||||
video_url = request.data.get('video_url')
|
||||
|
||||
if not video_url:
|
||||
# 创建模拟的视频URL和ID
|
||||
platform_account = video.platform_account
|
||||
platform_name = platform_account.platform_name
|
||||
|
||||
# 创建模拟的视频URL和ID
|
||||
video_url = f"https://example.com/{platform_name}/{video.id}"
|
||||
video_id = f"VID_{video.id}"
|
||||
|
||||
# 更新视频状态
|
||||
video.status = 'published'
|
||||
video.publish_time = timezone.now()
|
||||
video.video_url = video_url
|
||||
video.video_id = video_id
|
||||
video.video_id = f"VID_{video.id}"
|
||||
video.save()
|
||||
|
||||
logger.info(f"视频 {video.id} 已手动发布")
|
||||
|
||||
# 更新知识库文档
|
||||
platform_account = video.platform_account
|
||||
operator = platform_account.operator
|
||||
|
||||
knowledge_base = KnowledgeBase.objects.filter(
|
||||
name__contains=operator.real_name,
|
||||
type='private'
|
||||
).first()
|
||||
|
||||
if knowledge_base:
|
||||
document = KnowledgeBaseDocument.objects.filter(
|
||||
knowledge_base=knowledge_base,
|
||||
document_name__contains=video.title,
|
||||
status='active'
|
||||
).first()
|
||||
|
||||
if document:
|
||||
logger.info(f"应当更新文档 {document.document_id} 的视频发布状态")
|
||||
|
||||
return Response({
|
||||
"code": 200,
|
||||
"message": "视频发布成功",
|
||||
|
@ -159,8 +159,13 @@ REST_FRAMEWORK = {
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
],
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
]
|
||||
'rest_framework.permissions.AllowAny',
|
||||
],
|
||||
'DEFAULT_PARSER_CLASSES': [
|
||||
'rest_framework.parsers.JSONParser',
|
||||
'rest_framework.parsers.FormParser',
|
||||
'rest_framework.parsers.MultiPartParser'
|
||||
],
|
||||
}
|
||||
|
||||
# Channels 配置
|
||||
@ -280,21 +285,7 @@ SESSION_COOKIE_SECURE = False # 开发环境设置为 False
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
|
||||
# REST Framework 配置
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication', # WebSocket 需要
|
||||
],
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
],
|
||||
'DEFAULT_PARSER_CLASSES': [
|
||||
'rest_framework.parsers.JSONParser',
|
||||
'rest_framework.parsers.FormParser',
|
||||
'rest_framework.parsers.MultiPartParser'
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# Gmail API配置
|
||||
GOOGLE_CLOUD_PROJECT = 'knowledge-454905' # 更新为当前使用的项目ID
|
||||
|
Loading…
Reference in New Issue
Block a user