api_prepare.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. from django.contrib import auth
  2. from rest_framework.views import APIView
  3. from rest_framework.response import Response
  4. from rest_framework import status
  5. from rest_framework.authtoken.models import Token
  6. from rest_framework.authentication import BasicAuthentication, TokenAuthentication
  7. from .serializers import UserRegisterSerializer
  8. from django.middleware.csrf import get_token
  9. from django.contrib.auth import login
  10. from api.utils import *
  11. from api.models import File, Mission, Plan, Algorithm
  12. import json
  13. import logging
  14. logger = logging.getLogger('prepare')
  15. class UploadFileAPI(APIView):
  16. def get(self, request):
  17. user = request.user
  18. history = File.objects.getHistory(user=user)
  19. if history == FAILED:
  20. return failed(message="获取文件上传历史失败")
  21. else:
  22. return success(data=history)
  23. def post(self, request):
  24. user = request.user
  25. # 获取上传的文件对象
  26. nodeFileName = request.data.get('nodeFileName')
  27. edgeFileName = request.data.get('edgeFileName')
  28. nodeFile = request.data.get('nodes')
  29. edgeFile = request.data.get('edges')
  30. # 检查文件用途并进行响应处理
  31. file_usage = request.data.get('usage')
  32. if file_usage == 'input':
  33. pass
  34. else:
  35. return failed(message=filename + "上传失败 暂时只支持上传图处理原料文件")
  36. # 检查文件类型并进行相应处理
  37. file_type = request.data.get('type')
  38. for filename in [nodeFileName, edgeFileName]:
  39. if file_type == 'csv':
  40. if filename.split('.')[-1] != 'csv':
  41. return failed(message=filename + "上传失败 文件类型和文件后缀名不匹配")
  42. else:
  43. return failed(message=filename + "上传失败 暂不支持CSV之外文件")
  44. successUploadedFiles = []
  45. pre_file = None
  46. for filename, fileData in [[edgeFileName, edgeFile], [nodeFileName, nodeFile]]:
  47. # 处理数据库中记录
  48. file = File()
  49. file.name = filename
  50. file.user = request.user
  51. file.type = file_type
  52. file.usage = file_usage
  53. # 一定先edge再node
  54. if pre_file == None:
  55. file.content = 'edge'
  56. else:
  57. file.content = 'node'
  58. file.save()
  59. # 尝试保存文件
  60. result = file.storage(fileData)
  61. if result != OK:
  62. file.delete()
  63. # 第二个文件错误,同样删除第一个文件
  64. if pre_file:
  65. pre_file.delete()
  66. if result == FILE_ALREADY_EXIST:
  67. return failed(message=filename + "上传失败 已存在同名文件", data="已存在同名文件", code=400)
  68. elif result == FILE_FAILED_CREATE_DIR:
  69. return failed(message=filename + "上传失败 文件目录创建失败", data="文件目录创建失败", code=400)
  70. else:
  71. return failed(message=filename + "上传失败 因未知原因文件上传失败", data="因未知原因文件上传失败", code=400)
  72. # 第二个文件也成功时,将两个文件互相关联
  73. if pre_file:
  74. file.associate = pre_file
  75. pre_file.associate = file
  76. file.saveWithInfo()
  77. pre_file.saveWithInfo()
  78. else:
  79. pre_file = file
  80. # 两个文件均上传成功后,检测文件内容是否符合规范
  81. if file.checkIllegal() and pre_file.checkIllegal():
  82. # 确保正确后创建mission,并将信息返回
  83. mission = Mission()
  84. mission.nodeFile = file
  85. mission.edgeFile = pre_file
  86. mission.user = user
  87. mission.save()
  88. successUploadedFiles.append({
  89. "id": mission.id,
  90. "name": mission.name,
  91. "content": "mission",
  92. })
  93. # 初步对文件内容进行分析,获取节点和边的基本数据
  94. for file in [file, pre_file]:
  95. successUploadedFiles.append({
  96. "id": file.id,
  97. "name": file.name,
  98. "content": file.content,
  99. "nodes": file.own_file_info.nodes,
  100. "sNodes": file.own_file_info.sNodes,
  101. "dNodes": file.own_file_info.dNodes,
  102. "iNodes": file.own_file_info.iNodes,
  103. "edges": file.own_file_info.edges,
  104. })
  105. return success(message="文件上传成功", data=successUploadedFiles, code=200)
  106. else:
  107. return failed(message="文件合法性检查失败")
  108. def delete(self, request):
  109. user = request.user
  110. file = File.objects.get(id=request.data.get('id'))
  111. result = file.deleteStorage()
  112. if result == OK:
  113. return success(message="删除文件成功")
  114. elif result == False:
  115. return failed(messgae="删除文件失败")
  116. class InputFileAPI(APIView):
  117. def post(self, request):
  118. user = request.user
  119. nodes = request.data.get('nodes')
  120. edges = request.data.get('edges')
  121. logger.info(nodes)
  122. logger.info(edges)
  123. # 保存节点文件
  124. # 当前设置输入的节点信息仅包含一个名称
  125. nodesFile = File.objects.create(type='csv', usage='input', user=user, content='node')
  126. try:
  127. nodesCsvList = []
  128. for node in nodes:
  129. nodeList = [int(node['id']), str(node['type'])]
  130. for key in [k for k in node if k not in ['id', 'type']]:
  131. nodeList.append(str(key) + ':' +str(node[key]))
  132. nodesCsvList.append(nodeList)
  133. logger.info(nodesCsvList)
  134. nodesFile.generate(nodesCsvList)
  135. except Exception:
  136. # 回退操作
  137. logger.error(f"从输入信息创建节点文件失败 Error:{Exception}")
  138. nodesFile.delete()
  139. # 保存边文件
  140. edgesFile = File.objects.create(type='csv', usage='input', user=user, content='edge')
  141. try:
  142. edgesCsvList = []
  143. for edge in edges:
  144. # 边中应至少有source和target两个参数
  145. edgeList = [int(edge['source']), int(edge['target'])]
  146. for key in [k for k in edge if k not in ['source', 'target']]:
  147. edgeList.append(str(key) + ':' + str(edge[key]))
  148. edgesCsvList.append(edgeList)
  149. logger.info(edgesCsvList)
  150. edgesFile.generate(edgesCsvList)
  151. except Exception:
  152. # 回退操作
  153. logger.error(f"从输入信息创建边文件失败 Error:{Exception}")
  154. nodesFile.delete()
  155. edgesFile.delete()
  156. # 节点和边均保存成功,可以互相关联并创建mission
  157. nodesFile.associate = edgesFile
  158. edgesFile.associate = nodesFile
  159. # 计算节点和边的信息,生成fileInfo
  160. nodesFile.saveWithInfo()
  161. edgesFile.saveWithInfo()
  162. # 构造mission并返回完整信息
  163. successUploadedFiles = []
  164. if nodesFile.checkIllegal() and edgesFile.checkIllegal():
  165. # 确保正确后创建mission,并将信息返回
  166. mission = Mission()
  167. mission.nodeFile = nodesFile
  168. mission.edgeFile = edgesFile
  169. mission.user = user
  170. mission.save()
  171. successUploadedFiles.append({
  172. "id": mission.id,
  173. "name": mission.name,
  174. "content": "mission",
  175. })
  176. # 初步对文件内容进行分析,获取节点和边的基本数据
  177. for file in [nodesFile, edgesFile]:
  178. successUploadedFiles.append({
  179. "id": file.id,
  180. "name": file.name,
  181. "content": file.content,
  182. "nodes": file.own_file_info.nodes,
  183. "sNodes": file.own_file_info.sNodes,
  184. "dNodes": file.own_file_info.dNodes,
  185. "iNodes": file.own_file_info.iNodes,
  186. "edges": file.own_file_info.edges,
  187. })
  188. return success(message="文件上传成功", data=successUploadedFiles, code=200)
  189. else:
  190. logger.error("节点和边文件的合法性检测未通过")
  191. nodesFile.delete()
  192. edgesFile.delete()
  193. return failed(message="节点和边信息输入失败,节点或边信息未通过合法性检测")
  194. class PlanAPI(APIView):
  195. def post(self, request):
  196. user = request.user
  197. plans = request.data.get('plans')
  198. overWritePlans = False
  199. try:
  200. mission = Mission.objects.get(id=request.data.get('mission'))
  201. except Mission.DoesNotExist:
  202. print("处理规划所属任务不存在")
  203. return failed(message="未找到规划任务所属任务")
  204. # 重复提交同一Mission的规划将覆盖
  205. if mission.own_plans.exists():
  206. overWritePlans = True
  207. for plan in mission.own_plans.all():
  208. plan.delete()
  209. # 全部放入矩阵
  210. planMat = [[{}, {}, {}] for i in range(10)]
  211. # 找出所有并行的源头
  212. origins = []
  213. for plan in plans:
  214. if plan['row'] == 0:
  215. origins.append(plan)
  216. planMat[plan['row']][plan['col']] = plan
  217. rootPlan = Plan(mission=mission, parent=None, algorithm=None, user=user)
  218. rootPlan.save()
  219. originPlans = []
  220. # 将新建的plan的id都要返回
  221. createdPlans = []
  222. # 添加第一代规划
  223. for pJson in origins:
  224. # p.algorithm应该用来新建plan,先占位
  225. # childPlan = Plan(mission=mission, parent=rootPlan, algorithm=p['algorithm'], user=user)
  226. try:
  227. algorithm = Algorithm.objects.get(name=pJson['algorithm'])
  228. except Algorithm.DoesNotExist:
  229. print("Not Exist Algorithm")
  230. return failed(message=str(pJson['id']) + "规划选定算法不存在")
  231. pModel = Plan(mission=mission, parent=rootPlan, algorithm=algorithm, user=user)
  232. pModel.save()
  233. createdPlans.append({
  234. 'id': pModel.id,
  235. 'col': pJson['col'],
  236. 'row': pJson['row'],
  237. })
  238. # p是json数据,headPlan是保存的PlanModel
  239. originPlans.append([pJson, pModel])
  240. # 添加后续规划
  241. while originPlans:
  242. pJson, pModel = originPlans.pop()
  243. for childPos in pJson['children']:
  244. childJson = planMat[childPos['row']][childPos['col']]
  245. try:
  246. algorithm = Algorithm.objects.get(name=childJson['algorithm'])
  247. except Algorithm.DoesNotExist:
  248. print("Not Exist Algorithm")
  249. return failed(message=str(pJson['id']) + "规划选定算法不存在")
  250. childModel = Plan(mission=mission, parent=pModel, algorithm=algorithm, user=user)
  251. childModel.save()
  252. # 将新建的plan加入列表
  253. createdPlans.append({
  254. 'id': childModel.id,
  255. 'col': childPos['col'],
  256. 'row': childPos['row'],
  257. 'parentId': pModel.id,
  258. })
  259. originPlans.append([childJson, childModel])
  260. if overWritePlans:
  261. return success(message="规划已覆盖", data=createdPlans)
  262. else:
  263. return success(message="规划已提交", data=createdPlans)
  264. class MissionsAPI(APIView):
  265. def get(self, request):
  266. user = request.user
  267. missions = Mission.objects.filter(user=user).all()
  268. response = []
  269. for mission in missions:
  270. nodesInfo = mission.nodeFile.own_file_info
  271. edgesInfo = mission.edgeFile.own_file_info
  272. response.append({
  273. 'id': mission.id,
  274. 'name': mission.name,
  275. 'createTime': mission.create_time,
  276. 'nodesInfo': {
  277. 'S': nodesInfo.sNodes,
  278. 'D': nodesInfo.dNodes,
  279. 'I': nodesInfo.iNodes,
  280. },
  281. 'edgesInfo': {
  282. 'num': edgesInfo.edges,
  283. },
  284. # 防止近义词错误
  285. 'status': mission.state,
  286. 'state': mission.state,
  287. })
  288. return success(data=response)