from django.contrib import auth from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from rest_framework.authtoken.models import Token from rest_framework.authentication import BasicAuthentication, TokenAuthentication from .serializers import UserRegisterSerializer from django.middleware.csrf import get_token from django.contrib.auth import login from api.utils import * from api.models import File, Mission, Plan, Algorithm import json import logging logger = logging.getLogger('prepare') class UploadFileAPI(APIView): def get(self, request): user = request.user history = File.objects.getHistory(user=user) if history == FAILED: return failed(message="获取文件上传历史失败") else: return success(data=history) def post(self, request): user = request.user # 获取上传的文件对象 nodeFileName = request.data.get('nodeFileName') edgeFileName = request.data.get('edgeFileName') nodeFile = request.data.get('nodes') edgeFile = request.data.get('edges') # 检查文件用途并进行响应处理 file_usage = request.data.get('usage') if file_usage == 'input': pass else: return failed(message=filename + "上传失败 暂时只支持上传图处理原料文件") # 检查文件类型并进行相应处理 file_type = request.data.get('type') for filename in [nodeFileName, edgeFileName]: if file_type == 'csv': if filename.split('.')[-1] != 'csv': return failed(message=filename + "上传失败 文件类型和文件后缀名不匹配") else: return failed(message=filename + "上传失败 暂不支持CSV之外文件") successUploadedFiles = [] pre_file = None for filename, fileData in [[edgeFileName, edgeFile], [nodeFileName, nodeFile]]: # 处理数据库中记录 file = File() file.name = filename file.user = request.user file.type = file_type file.usage = file_usage # 一定先edge再node if pre_file == None: file.content = 'edge' else: file.content = 'node' file.save() # 尝试保存文件 result = file.storage(fileData) if result != OK: file.delete() # 第二个文件错误,同样删除第一个文件 if pre_file: pre_file.delete() if result == FILE_ALREADY_EXIST: return failed(message=filename + "上传失败 已存在同名文件", data="已存在同名文件", code=400) elif result == FILE_FAILED_CREATE_DIR: return failed(message=filename + "上传失败 文件目录创建失败", data="文件目录创建失败", code=400) else: return failed(message=filename + "上传失败 因未知原因文件上传失败", data="因未知原因文件上传失败", code=400) # 第二个文件也成功时,将两个文件互相关联 if pre_file: file.associate = pre_file pre_file.associate = file file.saveWithInfo() pre_file.saveWithInfo() else: pre_file = file # 两个文件均上传成功后,检测文件内容是否符合规范 if file.checkIllegal() and pre_file.checkIllegal(): # 确保正确后创建mission,并将信息返回 mission = Mission() mission.nodeFile = file mission.edgeFile = pre_file mission.user = user mission.save() successUploadedFiles.append({ "id": mission.id, "name": mission.name, # 防止近义词错误 "state": mission.state, "status": mission.state, "content": "mission", }) # 初步对文件内容进行分析,获取节点和边的基本数据 for file in [file, pre_file]: successUploadedFiles.append({ "id": file.id, "name": file.name, "content": file.content, "nodes": file.own_file_info.nodes, "sNodes": file.own_file_info.sNodes, "dNodes": file.own_file_info.dNodes, "iNodes": file.own_file_info.iNodes, "edges": file.own_file_info.edges, }) return success(message="文件上传成功", data=successUploadedFiles, code=200) else: return failed(message="文件合法性检查失败") def delete(self, request): user = request.user file = File.objects.get(id=request.data.get('id')) result = file.deleteStorage() if result == OK: return success(message="删除文件成功") elif result == False: return failed(messgae="删除文件失败") class InputFileAPI(APIView): def post(self, request): user = request.user nodes = request.data.get('nodes') edges = request.data.get('edges') logger.info(nodes) logger.info(edges) # 保存节点文件 # 当前设置输入的节点信息仅包含一个名称 nodesFile = File.objects.create(type='csv', usage='input', user=user, content='node') try: nodesCsvList = [] for node in nodes: nodeList = [int(node['id']), str(node['type'])] for key in [k for k in node if k not in ['id', 'type']]: nodeList.append(str(key) + ':' +str(node[key])) nodesCsvList.append(nodeList) logger.info(nodesCsvList) nodesFile.generate(nodesCsvList) except Exception: # 回退操作 logger.error(f"从输入信息创建节点文件失败 Error:{Exception}") nodesFile.delete() # 保存边文件 edgesFile = File.objects.create(type='csv', usage='input', user=user, content='edge') try: edgesCsvList = [] for edge in edges: # 边中应至少有source和target两个参数 edgeList = [int(edge['source']), int(edge['target'])] for key in [k for k in edge if k not in ['source', 'target']]: edgeList.append(str(key) + ':' + str(edge[key])) edgesCsvList.append(edgeList) logger.info(edgesCsvList) edgesFile.generate(edgesCsvList) except Exception: # 回退操作 logger.error(f"从输入信息创建边文件失败 Error:{Exception}") nodesFile.delete() edgesFile.delete() # 节点和边均保存成功,可以互相关联并创建mission nodesFile.associate = edgesFile edgesFile.associate = nodesFile # 计算节点和边的信息,生成fileInfo nodesFile.saveWithInfo() edgesFile.saveWithInfo() # 构造mission并返回完整信息 successUploadedFiles = [] if nodesFile.checkIllegal() and edgesFile.checkIllegal(): # 确保正确后创建mission,并将信息返回 mission = Mission() mission.nodeFile = nodesFile mission.edgeFile = edgesFile mission.user = user mission.state = 'init' mission.save() successUploadedFiles.append({ "id": mission.id, "name": mission.name, "content": "mission", }) # 初步对文件内容进行分析,获取节点和边的基本数据 for file in [nodesFile, edgesFile]: successUploadedFiles.append({ "id": file.id, "name": file.name, "content": file.content, "nodes": file.own_file_info.nodes, "sNodes": file.own_file_info.sNodes, "dNodes": file.own_file_info.dNodes, "iNodes": file.own_file_info.iNodes, "edges": file.own_file_info.edges, }) return success(message="文件上传成功", data=successUploadedFiles, code=200) else: logger.error("节点和边文件的合法性检测未通过") nodesFile.delete() edgesFile.delete() return failed(message="节点和边信息输入失败,节点或边信息未通过合法性检测") class PlanAPI(APIView): def get(self, request): user = request.user try: mission = Mission.objects.get(id=request.GET.get('mission')) except Mission.DoesNotExist: logger.error(f"处理规划所属任务不存在{request.GET.get('mission')}") return failed(message="未找到规划任务所属任务") plans = mission.own_plans.all() response = [] for plan in plans: if plan.parent: response.append({ 'id': plan.id, 'parent': plan.parent.id, # 使用名称检索算法 'algorithm': plan.algorithm.name, }) else: response.append({ 'id': plan.id, 'parent': None, # 使用名称检索算法 'algorithm': None, }) return success(data=response) def post(self, request): user = request.user plans = request.data.get('plans') overWritePlans = False try: mission = Mission.objects.get(id=request.data.get('mission')) except Mission.DoesNotExist: logger.error("处理规划所属任务不存在") return failed(message="未找到规划任务所属任务") # 重复提交同一Mission的规划将覆盖 if mission.own_plans.exists(): overWritePlans = True for plan in mission.own_plans.all(): plan.delete() # 全部放入矩阵 planMat = [[{}, {}, {}] for i in range(10)] # 找出所有并行的源头 origins = [] for plan in plans: if plan['row'] == 0: origins.append(plan) planMat[plan['row']][plan['col']] = plan rootPlan = Plan(mission=mission, parent=None, algorithm=None, user=user) rootPlan.save() originPlans = [] # 将新建的plan的id都要返回 createdPlans = [] # 添加第一代规划 for pJson in origins: # p.algorithm应该用来新建plan,先占位 # childPlan = Plan(mission=mission, parent=rootPlan, algorithm=p['algorithm'], user=user) try: algorithm = Algorithm.objects.get(name=pJson['algorithm']) except Algorithm.DoesNotExist: logger.error("传递算法不存在") return failed(message=str(pJson['id']) + "规划选定算法不存在") pModel = Plan(mission=mission, parent=rootPlan, algorithm=algorithm, user=user) pModel.save() createdPlans.append({ 'id': pModel.id, 'col': pJson['col'], 'row': pJson['row'], }) # p是json数据,headPlan是保存的PlanModel originPlans.append([pJson, pModel]) # 添加后续规划 while originPlans: pJson, pModel = originPlans.pop() for childPos in pJson['children']: childJson = planMat[childPos['row']][childPos['col']] try: algorithm = Algorithm.objects.get(name=childJson['algorithm']) except Algorithm.DoesNotExist: logger.error("传递算法不存在") return failed(message=str(pJson['id']) + "规划选定算法不存在") childModel = Plan(mission=mission, parent=pModel, algorithm=algorithm, user=user) childModel.save() # 将新建的plan加入列表 createdPlans.append({ 'id': childModel.id, 'col': childPos['col'], 'row': childPos['row'], 'parentId': pModel.id, }) originPlans.append([childJson, childModel]) if overWritePlans: return success(message="规划已覆盖", data=createdPlans) else: return success(message="规划已提交", data=createdPlans) class MissionsAPI(APIView): def get(self, request): user = request.user missions = Mission.objects.filter(user=user).all() response = [] for mission in missions: nodesInfo = mission.nodeFile.own_file_info edgesInfo = mission.edgeFile.own_file_info response.append({ 'id': mission.id, 'name': mission.name, 'createTime': mission.create_time, 'nodesInfo': { 'S': nodesInfo.sNodes, 'D': nodesInfo.dNodes, 'I': nodesInfo.iNodes, }, 'edgesInfo': { 'num': edgesInfo.edges, }, # 防止近义词错误 'status': mission.state, 'state': mission.state, }) return success(data=response)