VersionManagementController.py 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import hashlib
  4. import json
  5. import os
  6. import threading
  7. import time
  8. import boto3
  9. import botocore
  10. import requests
  11. from django.core.paginator import Paginator
  12. from django.db import transaction
  13. from django.views.generic.base import View
  14. from packaging import version as pacVer
  15. from Ansjer.config import BASE_DIR, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
  16. from Ansjer.config import LOGGER, CONFIG_TEST, SERVER_DOMAIN, CONFIG_CN, CONFIG_INFO
  17. from Model.models import Equipment_Version, App_Info, AppSetModel, App_Colophon, Pc_Info, CountryModel, \
  18. Device_Info, UidSetModel, Device_User, IPAddr, DeviceVersionInfo, iotdeviceInfoModel
  19. from Object.RedisObject import RedisObject
  20. from Object.ResponseObject import ResponseObject
  21. from Object.TokenObject import TokenObject
  22. from Object.UrlTokenObject import UrlTokenObject
  23. from Service.CommonService import CommonService
  24. class VersionManagement(View):
  25. def get(self, request, *args, **kwargs):
  26. request.encoding = 'utf-8'
  27. operation = kwargs.get('operation')
  28. return self.validation(request.GET, request, operation)
  29. def post(self, request, *args, **kwargs):
  30. request.encoding = 'utf-8'
  31. operation = kwargs.get('operation')
  32. return self.validation(request.POST, request, operation)
  33. def validation(self, request_dict, request, operation):
  34. language = request_dict.get('language', 'en')
  35. response = ResponseObject(language, 'pc')
  36. if operation == 'upLoadFile':
  37. return self.upLoadFile(request, request_dict, response)
  38. else:
  39. tko = TokenObject(
  40. request.META.get('HTTP_AUTHORIZATION'),
  41. returntpye='pc')
  42. if tko.code != 0:
  43. return response.json(tko.code)
  44. response.lang = tko.lang
  45. userID = tko.userID
  46. if operation == 'getEquipmentVersionList':
  47. return self.getEquipmentVersionList(request_dict, response)
  48. elif operation == 'editVersionInformation':
  49. return self.editVersionInformation(request_dict, response)
  50. elif operation == 'deleteEquipmentVersion':
  51. return self.deleteEquipmentVersion(request_dict, response)
  52. elif operation == 'getAppVersionList':
  53. return self.getAppVersionList(request_dict, response)
  54. elif operation == 'addOrEditAppInfo':
  55. return self.addOrEditAppInfo(request_dict, response)
  56. elif operation == 'deleteAppVersion':
  57. return self.deleteAppVersion(request_dict, response)
  58. elif operation == 'getAppSet':
  59. return self.getAppSet(request_dict, response)
  60. elif operation == 'editAppSet':
  61. return self.editAppSet(request_dict, response)
  62. elif operation == 'getAppRecordList':
  63. return self.getAppRecordList(request_dict, response)
  64. elif operation == 'getAppBundleIdList':
  65. return self.getAppBundleIdList(request_dict, response)
  66. elif operation == 'addOrEditAppRecord':
  67. return self.addOrEditAppRecord(request_dict, response)
  68. elif operation == 'deleteAppRecord':
  69. return self.deleteAppRecord(request_dict, response)
  70. elif operation == 'getPcInfoList':
  71. return self.getPcInfoList(request_dict, response)
  72. elif operation == 'editPcVersion':
  73. return self.editPcVersion(request_dict, response)
  74. elif operation == 'deletePcInfo':
  75. return self.deletePcInfo(request_dict, response)
  76. elif operation == 'getCountryList':
  77. return self.getCountryList(request_dict, response)
  78. elif operation == 'deviceAutoUpdate':
  79. return self.device_auto_update(userID, request_dict, response)
  80. else:
  81. return response.json(404)
  82. def getEquipmentVersionList(self, request_dict, response):
  83. mci = request_dict.get('mci', None)
  84. lang = request_dict.get('lang', None)
  85. version = request_dict.get('version', None)
  86. pageNo = request_dict.get('pageNo', None)
  87. pageSize = request_dict.get('pageSize', None)
  88. if not all([pageNo, pageSize]):
  89. return response.json(444)
  90. page = int(pageNo)
  91. line = int(pageSize)
  92. try:
  93. equipment_version_qs = Equipment_Version.objects.filter().order_by('-update_time')
  94. if mci:
  95. equipment_version_qs = equipment_version_qs.filter(mci=mci)
  96. if lang:
  97. equipment_version_qs = equipment_version_qs.filter(lang=lang)
  98. if version:
  99. equipment_version_qs = equipment_version_qs.filter(version__contains=version)
  100. total = equipment_version_qs.count()
  101. equipment_version_qs = equipment_version_qs.values()[(page - 1) * line:page * line]
  102. equipment_version_list = CommonService.qs_to_list(equipment_version_qs)
  103. for equipment_version in equipment_version_list:
  104. new_equipment_version = equipment_version['version'][1:]
  105. d_code = new_equipment_version.rsplit('.', 1)[1]
  106. software_ver = new_equipment_version.rsplit('.', 1)[0].replace('V', '')
  107. device_ver_info_qs = DeviceVersionInfo.objects.filter(d_code=d_code, software_ver=software_ver)
  108. if device_ver_info_qs.exists():
  109. equipment_version['is_hav_dev_ver_info'] = 1
  110. else:
  111. equipment_version['is_hav_dev_ver_info'] = 0
  112. return response.json(0, {'list': equipment_version_list, 'total': total})
  113. except Exception as e:
  114. print(e)
  115. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  116. def upLoadFile(self, request, request_dict, response):
  117. file = request.FILES.get('file', None)
  118. mci = request_dict.get('mci', '')
  119. lang = request_dict.get('lang', '')
  120. ESN = request_dict.get('ESN', '')
  121. max_ver = request_dict.get('max_ver', '')
  122. channel = request_dict.get('channel', '')
  123. resolutionRatio = request_dict.get('resolutionRatio', '')
  124. Description = request_dict.get('Description', '')
  125. status = request_dict.get('status', 0)
  126. isPopup = request_dict.get('isPopup', 0)
  127. auto_update = request_dict.get('autoUpdate', 0)
  128. data_json = request_dict.get('dataJson', None)
  129. if not all([file, mci, lang, ESN, max_ver, channel, resolutionRatio]):
  130. return response.json(444)
  131. try:
  132. with transaction.atomic():
  133. nowTime = CommonService.timestamp_to_str(timestamp=int(time.time()))
  134. channel = int(channel)
  135. resolutionRatio = int(resolutionRatio)
  136. status = int(status)
  137. isPopup = int(isPopup)
  138. if data_json:
  139. data_json = eval(data_json)
  140. # 文件名为设备版本,最后一个'.'的前面为软件版本,后面为设备规格名称
  141. # V2.2.4.16E201252CA,软件版本:2.2.4,设备规格名称:16E201252CA
  142. # V1.7.2.36C11680X30411F000600000150001Z,软件版本:1.7.2,设备规格名称:36C11680X30411F000600000150001Z
  143. file_name = str(file) # 文件名
  144. # .img和.tar.gz文件
  145. file_type_index = file_name.find('.img')
  146. if file_type_index == -1:
  147. file_type_index = file_name.find('.tar')
  148. if file_type_index == -1:
  149. return response.json(903)
  150. version = file_name[:file_type_index] # 设备版本
  151. version_index = version.rindex('.')
  152. softwareVersion = version[1:version_index] # 软件版本
  153. code = version[version_index + 1:] # 设备规格名称
  154. chipModelList2Code = code[:4] # 主芯片
  155. type = code[8:10] # 设备机型
  156. companyCode = code[-1:] # 公司代码
  157. fileSize = file.size
  158. filePath = '/'.join(('static/otapack', mci, lang, file_name))
  159. file_data = file.read()
  160. fileMd5 = hashlib.md5(file_data).hexdigest()
  161. data_dict = {'mci': mci, 'lang': lang, 'ESN': ESN, 'max_ver': max_ver, 'channel': channel,
  162. 'resolutionRatio': resolutionRatio, 'Description': Description, 'status': status,
  163. 'is_popup': isPopup, 'version': version, 'softwareVersion': softwareVersion, 'code': code,
  164. 'chipModelList2Code': chipModelList2Code, 'type': type, 'companyCode': companyCode,
  165. 'fileSize': fileSize, 'filePath': filePath, 'fileMd5': fileMd5, 'update_time': nowTime,
  166. 'data_json': data_json, 'auto_update': auto_update}
  167. # Equipment_Version表创建或更新数据
  168. equipment_version_qs = Equipment_Version.objects.filter(code=code, lang=lang)
  169. if not equipment_version_qs.exists():
  170. Equipment_Version.objects.create(eid=CommonService.getUserID(getUser=False, setOTAID=True),
  171. **data_dict)
  172. else:
  173. equipment_version_qs.update(**data_dict)
  174. # 上传文件到服务器
  175. upload_path = '/'.join((BASE_DIR, 'static/otapack', mci, lang)).replace('\\', '/') + '/'
  176. if not os.path.exists(upload_path): # 上传目录不存在则创建
  177. os.makedirs(upload_path)
  178. # 文件上传
  179. full_name = upload_path + file_name
  180. if os.path.exists(full_name): # 删除同名文件
  181. os.remove(full_name)
  182. with open(full_name, 'wb+') as write_file:
  183. for chunk in file.chunks():
  184. write_file.write(chunk)
  185. LOGGER.info('versionManagement/upLoadFile成功上传{}'.format(file_name))
  186. if not DeviceVersionInfo.objects.filter(d_code=code, software_ver=softwareVersion).exists():
  187. return response.json(0, "该版本尚未添加设备版本信息")
  188. return response.json(0)
  189. except Exception as e:
  190. LOGGER.info(
  191. 'versionManagement/upLoadFile接口异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  192. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  193. def editVersionInformation(self, request_dict, response):
  194. eid = request_dict.get('eid', None)
  195. ESN = request_dict.get('ESN', '')
  196. max_ver = request_dict.get('max_ver', '')
  197. status = request_dict.get('status', '')
  198. channel = request_dict.get('channel', '')
  199. resolutionRatio = request_dict.get('resolutionRatio', '')
  200. Description = request_dict.get('Description', '')
  201. is_popup = request_dict.get('is_popup', '')
  202. auto_update = request_dict.get('autoUpdate', 0)
  203. data_json = request_dict.get('dataJson', None)
  204. if not eid:
  205. return response.json(444)
  206. status = 1 if status == 'true' else 0
  207. if data_json:
  208. data_json = eval(data_json)
  209. try:
  210. equipment_version_qs = Equipment_Version.objects.filter(eid=eid)
  211. if not equipment_version_qs.exists():
  212. return response.json(173)
  213. data_dict = {'ESN': ESN, 'max_ver': max_ver, 'status': status, 'channel': channel,
  214. 'auto_update': auto_update, 'data_json': data_json,
  215. 'resolutionRatio': resolutionRatio, 'Description': Description, 'is_popup': is_popup}
  216. equipment_version_qs.update(**data_dict)
  217. return response.json(0)
  218. except Exception as e:
  219. print(e)
  220. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  221. def deleteEquipmentVersion(self, request_dict, response):
  222. eid = request_dict.get('eid', None)
  223. if not eid:
  224. return response.json(444)
  225. try:
  226. equipment_version_qs = Equipment_Version.objects.filter(eid=eid)
  227. filePath = equipment_version_qs.values('filePath')[0]['filePath']
  228. equipment_version_qs.delete()
  229. # 删除文件
  230. full_name = '/'.join((BASE_DIR, filePath)).replace('\\', '/')
  231. if os.path.exists(full_name):
  232. os.remove(full_name)
  233. return response.json(0)
  234. except Exception as e:
  235. print(e)
  236. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  237. def getAppVersionList(self, request_dict, response):
  238. app_type = request_dict.get('app_type', None)
  239. appName = request_dict.get('appName', None)
  240. version = request_dict.get('version', None)
  241. pageNo = request_dict.get('pageNo', None)
  242. pageSize = request_dict.get('pageSize', None)
  243. if not all([pageNo, pageSize]):
  244. return response.json(444)
  245. page = int(pageNo)
  246. line = int(pageSize)
  247. try:
  248. app_info_qs = App_Info.objects.filter()
  249. if app_type:
  250. if app_type == 'IOS':
  251. app_type = 1
  252. elif app_type == '安卓':
  253. app_type = 2
  254. else:
  255. app_type = 3
  256. app_info_qs = app_info_qs.filter(app_type=app_type)
  257. if appName:
  258. app_info_qs = app_info_qs.filter(appName__contains=appName)
  259. if version:
  260. app_info_qs = app_info_qs.filter(version__contains=version)
  261. total = app_info_qs.count()
  262. app_info_qs = app_info_qs.values()[(page - 1) * line:page * line]
  263. app_info_list = CommonService.qs_to_list(app_info_qs)
  264. return response.json(0, {'list': app_info_list, 'total': total})
  265. except Exception as e:
  266. print(e)
  267. return response.json(500, repr(e))
  268. def addOrEditAppInfo(self, request_dict, response):
  269. id = request_dict.get('id', None)
  270. appName = request_dict.get('appName', '')
  271. appBundleId = request_dict.get('appBundleId', '')
  272. bundleVersion = request_dict.get('bundleVersion', '')
  273. newAppversion = request_dict.get('newAppversion', '')
  274. minAppversion = request_dict.get('minAppversion', '')
  275. content = request_dict.get('content', '')
  276. app_type = request_dict.get('app_type', '')
  277. downloadLink = request_dict.get('downloadLink', '')
  278. try:
  279. app_type = int(app_type)
  280. data_dict = {'appName': appName, 'appBundleId': appBundleId, 'bundleVersion': bundleVersion,
  281. 'newAppversion': newAppversion, 'minAppversion': minAppversion, 'content': content,
  282. 'app_type': app_type, 'downloadLink': downloadLink}
  283. if not id: # 添加
  284. App_Info.objects.create(**data_dict)
  285. else: # 编辑
  286. app_info_qs = App_Info.objects.filter(id=id)
  287. if not app_info_qs.exists():
  288. return response.json(173)
  289. app_info_qs.update(**data_dict)
  290. return response.json(0)
  291. except Exception as e:
  292. print(e)
  293. return response.json(500, repr(e))
  294. def deleteAppVersion(self, request_dict, response):
  295. appBundleId = request_dict.get('appBundleId', None)
  296. if not appBundleId:
  297. return response.json(444)
  298. try:
  299. App_Info.objects.filter(appBundleId=appBundleId).delete()
  300. AppSetModel.objects.filter(appBundleId=appBundleId).delete()
  301. return response.json(0)
  302. except Exception as e:
  303. print(e)
  304. return response.json(500, repr(e))
  305. def getAppSet(self, request_dict, response):
  306. appBundleId = request_dict.get('appBundleId', None)
  307. if not appBundleId:
  308. return response.json(444)
  309. try:
  310. app_set_qs = AppSetModel.objects.filter(appBundleId=appBundleId).values('content')
  311. if app_set_qs.exists():
  312. content = app_set_qs[0]['content']
  313. return response.json(0, {'content': content})
  314. else:
  315. nowTime = int(time.time())
  316. AppSetModel.objects.create(
  317. appBundleId=appBundleId,
  318. addTime=nowTime,
  319. updTime=nowTime
  320. )
  321. return response.json(0)
  322. except Exception as e:
  323. print(e)
  324. return response.json(500, repr(e))
  325. def editAppSet(self, request_dict, response):
  326. appBundleId = request_dict.get('appBundleId', None)
  327. content = request_dict.get('content', None)
  328. if not all([appBundleId, content]):
  329. return response.json(444)
  330. try:
  331. AppSetModel.objects.filter(appBundleId=appBundleId).update(content=content)
  332. return response.json(0)
  333. except Exception as e:
  334. print(e)
  335. return response.json(500, repr(e))
  336. def getAppRecordList_1(self, request_dict, response):
  337. app_type = request_dict.get('app_type', 'IOS')
  338. pageNo = request_dict.get('pageNo', None)
  339. pageSize = request_dict.get('pageSize', None)
  340. if not all([pageNo, pageSize]):
  341. return response.json(444)
  342. page = int(pageNo)
  343. line = int(pageSize)
  344. try:
  345. if app_type:
  346. if app_type == 'IOS':
  347. app_type = 1
  348. elif app_type == '安卓':
  349. app_type = 2
  350. else:
  351. app_type = 3
  352. app_colophon_qs = App_Colophon.objects.filter(app_id__app_type=app_type).order_by('app_id').values_list('app_id__appBundleId', flat=True).distinct()
  353. if not app_colophon_qs.exists():
  354. return response.json(173)
  355. total = app_colophon_qs.count()
  356. app_colophon_list = list(app_colophon_qs[(page - 1) * line:page * line])
  357. app_info_qs = App_Colophon.objects.filter(app_id__appBundleId__in=app_colophon_list).\
  358. values("id", "lang", "newApp_version", "content","version_time", "app_id__appBundleId", "app_id__appName", "app_id__app_type")
  359. app_info_list = list(app_info_qs)
  360. data_dict = {}
  361. # 组装数据
  362. for app_info in app_info_list:
  363. for app_colophon in app_colophon_list:
  364. if app_colophon not in data_dict.keys():
  365. data_dict[app_colophon] = []
  366. if app_colophon == app_info['app_id__appBundleId']:
  367. data_dict[app_colophon].append(app_info)
  368. for k, v in enumerate(data_dict):
  369. new = sorted(data_dict[v], key=lambda x: x['id'], reverse=True)
  370. data_dict[v] = new
  371. res = {
  372. 'data_dict': data_dict,
  373. 'total': total
  374. }
  375. return response.json(0, res)
  376. except Exception as e:
  377. print(e)
  378. return response.json(500, repr(e))
  379. def getAppRecordList(self, request_dict, response):
  380. app_type = request_dict.get('appType', 'IOS')
  381. queryVersion = request_dict.get('queryVersion', None)
  382. queryAppBundleId = request_dict.get('queryAppBundleId', None)
  383. pageNo = request_dict.get('pageNo', None)
  384. pageSize = request_dict.get('pageSize', None)
  385. if not all([pageNo, pageSize]):
  386. return response.json(444)
  387. page = int(pageNo)
  388. line = int(pageSize)
  389. try:
  390. if app_type == 'IOS':
  391. app_type = 1
  392. elif app_type == '安卓':
  393. app_type = 2
  394. else:
  395. app_type = 3
  396. app_colophon_qs = App_Colophon.objects.filter(app_id__app_type=app_type).order_by('app_id').values_list('app_id__appBundleId', flat=True).distinct()
  397. if not app_colophon_qs.exists():
  398. return response.json(173)
  399. total = app_colophon_qs.count()
  400. app_colophon_list = list(app_colophon_qs[(page - 1) * line:page * line])
  401. app_info_qs = App_Colophon.objects.filter(app_id__appBundleId__in=app_colophon_list).\
  402. values("id", "lang", "newApp_version", "content", "version_time", "app_id__appBundleId", "app_id__appName", "app_id__app_type")
  403. app_info_list = list(app_info_qs)
  404. app_record_list = [] # 响应的app record数据
  405. appBundleId_list = [] # 记录已添加过的appBundleId
  406. # 组装数据
  407. for app_info in app_info_list:
  408. version = app_info['lang'] + app_info['newApp_version']
  409. if app_info['app_id__appBundleId'] not in appBundleId_list:
  410. appBundleId_list.append(app_info['app_id__appBundleId'])
  411. newApp_version_list = [[app_info['lang'], app_info['newApp_version']]]
  412. app_record_dict = {
  413. 'app_id__appBundleId': app_info['app_id__appBundleId'],
  414. 'app_id__appName': app_info['app_id__appName'],
  415. 'app_id__app_type': app_info['app_id__app_type'],
  416. 'version': version,
  417. 'newApp_version_list': newApp_version_list,
  418. 'id': app_info['id'],
  419. 'content': app_info['content'],
  420. 'version_time': time.strftime("%Y-%m-%d", time.localtime(app_info['version_time'])),
  421. }
  422. if queryVersion and queryVersion == version and queryAppBundleId == app_info['app_id__appBundleId']:
  423. app_record_dict['id'] = app_info['id']
  424. app_record_dict['content'] = app_info['content']
  425. app_record_dict['version_time'] = time.strftime("%Y-%m-%d", time.localtime(app_info['version_time']))
  426. app_record_list.append(app_record_dict)
  427. else:
  428. index = appBundleId_list.index(app_info['app_id__appBundleId'])
  429. newApp_version_list = [app_info['lang'], app_info['newApp_version']]
  430. if queryVersion and queryVersion == version and queryAppBundleId == app_info['app_id__appBundleId']:
  431. # app_record_list里对应字典插入值
  432. app_record_list[index]['id'] = app_info['id']
  433. app_record_list[index]['content'] = app_info['content']
  434. app_record_list[index]['version_time'] = time.strftime("%Y-%m-%d", time.localtime(app_info['version_time']))
  435. app_record_list[index]['version'] = version
  436. app_record_list[index]['newApp_version_list'].insert(0, newApp_version_list)
  437. else:
  438. app_record_list[index]['newApp_version_list'].append(newApp_version_list)
  439. res = {
  440. 'app_record_list': app_record_list,
  441. 'total': total
  442. }
  443. return response.json(0, res)
  444. except Exception as e:
  445. print(e)
  446. return response.json(500, repr(e))
  447. def getAppBundleIdList(self, request_dict, response):
  448. print('request_dict:', request_dict)
  449. app_type = request_dict.get('appType', 'IOS')
  450. try:
  451. if app_type == 'IOS':
  452. app_type = 1
  453. elif app_type == '安卓':
  454. app_type = 2
  455. else:
  456. app_type = 3
  457. app_info_qs = App_Info.objects.filter(app_type=app_type).values('id', 'appBundleId')
  458. appBundleIdList = list(app_info_qs)
  459. return response.json(0, {'appBundleIdList': appBundleIdList})
  460. except Exception as e:
  461. print(e)
  462. return response.json(500, repr(e))
  463. def addOrEditAppRecord(self, request_dict, response):
  464. print('request_dict:', request_dict)
  465. appBundleId = request_dict.get('app_id__appBundleId', None)
  466. newApp_version = request_dict.get('version', None)
  467. version_time = request_dict.get('version_time', None)
  468. cn_content = request_dict.get('cnContent', None)
  469. en_content = request_dict.get('enContent', None)
  470. content = request_dict.get('content', None)
  471. app_colophon_id = request_dict.get('id', None)
  472. if not all([appBundleId, newApp_version, version_time]):
  473. return response.json(444)
  474. try:
  475. version_time = int(time.mktime(time.strptime(version_time, '%Y-%m-%d'))) # 字符串转时间戳
  476. if app_colophon_id: # 编辑
  477. # 编辑获取的版本信息前两位为语言
  478. lang = newApp_version[:2]
  479. newApp_version = newApp_version[2:]
  480. App_Colophon.objects.filter(id=app_colophon_id).update(lang=lang, newApp_version=newApp_version,
  481. content=content, version_time=version_time)
  482. else: # 添加
  483. app_info_qs = App_Info.objects.filter(appBundleId=appBundleId).values('id')
  484. if not app_info_qs.exists():
  485. return response.json(173)
  486. data_dict = {
  487. 'app_id_id': app_info_qs[0]['id'],
  488. 'newApp_version': newApp_version,
  489. 'version_time': version_time,
  490. 'lang': 'cn',
  491. 'content': cn_content,
  492. }
  493. with transaction.atomic():
  494. # 创建中文内容数据
  495. App_Colophon.objects.create(**data_dict)
  496. # 创建英文内容数据
  497. data_dict['lang'] = 'en'
  498. data_dict['content'] = en_content
  499. App_Colophon.objects.create(**data_dict)
  500. return response.json(0)
  501. except Exception as e:
  502. print(e)
  503. return response.json(500, repr(e))
  504. def deleteAppRecord(self, request_dict, response):
  505. print('request_dict:', request_dict)
  506. app_colophon_id = request_dict.get('app_colophon_id', None)
  507. try:
  508. if not app_colophon_id:
  509. return response.json(444)
  510. app_colophon_qs = App_Colophon.objects.filter(id=app_colophon_id)
  511. if not app_colophon_qs.exists():
  512. return response.json(173)
  513. app_colophon_qs.delete()
  514. return response.json(0)
  515. except Exception as e:
  516. print(e)
  517. return response.json(500, repr(e))
  518. def getPcInfoList(self, request_dict, response):
  519. print('request_dict:', request_dict)
  520. pc_name = request_dict.get('pcName', None)
  521. pageNo = request_dict.get('pageNo', None)
  522. pageSize = request_dict.get('pageSize', None)
  523. if not all([pageNo, pageSize]):
  524. return response.json(444)
  525. page = int(pageNo)
  526. line = int(pageSize)
  527. try:
  528. pc_info_qs = Pc_Info.objects.filter()
  529. if pc_name:
  530. pc_info_qs = Pc_Info.objects.filter(pc_name__contains=pc_name)
  531. if not pc_info_qs.exists():
  532. return response.json(173)
  533. total = pc_info_qs.count()
  534. pc_info_qs = pc_info_qs.values()[(page - 1) * line:page * line]
  535. pc_info_list = CommonService.qs_to_list(pc_info_qs)
  536. return response.json(0, {'list': pc_info_list, 'total': total})
  537. except Exception as e:
  538. print(e)
  539. return response.json(500, repr(e))
  540. def editPcVersion(self, request_dict, response):
  541. pc_info_id = request_dict.get('id', None)
  542. pc_name = request_dict.get('pc_name', '')
  543. bundle_version = request_dict.get('bundle_version', '')
  544. pc_version = request_dict.get('pc_version', '')
  545. pc_test = request_dict.get('pc_test', '')
  546. lang = request_dict.get('lang', '')
  547. file_type = request_dict.get('file_type', '')
  548. package = request_dict.get('package', '')
  549. explain = request_dict.get('explain', '')
  550. is_update = request_dict.get('is_update', '')
  551. is_open = request_dict.get('is_open', '')
  552. content = request_dict.get('content', '')
  553. authority = request_dict.get('authority', '')
  554. download_link = request_dict.get('download_link', '')
  555. if not pc_info_id:
  556. return response.json(444)
  557. try:
  558. pc_info_qs = Pc_Info.objects.filter(id=pc_info_id)
  559. if not pc_info_qs.exists():
  560. return response.json(173)
  561. data_dict = {
  562. 'pc_name': pc_name,
  563. 'bundle_version': bundle_version,
  564. 'pc_version': pc_version,
  565. 'pc_test': pc_test,
  566. 'lang': lang,
  567. 'file_type': file_type,
  568. 'package': package,
  569. 'explain': explain,
  570. 'is_update': is_update,
  571. 'is_open': is_open,
  572. 'content': content,
  573. 'authority': authority,
  574. 'download_link': download_link,
  575. }
  576. pc_info_qs.update(**data_dict)
  577. return response.json(0)
  578. except Exception as e:
  579. print(e)
  580. return response.json(500, repr(e))
  581. def deletePcInfo(self, request_dict, response):
  582. print('request_dict:', request_dict)
  583. pc_info_id = request_dict.get('id', None)
  584. try:
  585. if not pc_info_id:
  586. return response.json(444)
  587. pc_info_qs = Pc_Info.objects.filter(id=pc_info_id)
  588. if not pc_info_qs.exists():
  589. return response.json(173)
  590. # 删除存储桶的文件
  591. Key = pc_info_qs.values('download_link')[0]['download_link']
  592. pc_info_qs.delete()
  593. aws_s3_client = boto3.client(
  594. 's3',
  595. region_name='cn-northwest-1',
  596. aws_access_key_id=AWS_ACCESS_KEY_ID[0],
  597. aws_secret_access_key=AWS_SECRET_ACCESS_KEY[0],
  598. config=botocore.client.Config(signature_version='s3v4'),
  599. )
  600. try:
  601. aws_s3_client.delete_object(Bucket='pc-package', Key=Key)
  602. finally:
  603. return response.json(0)
  604. except Exception as e:
  605. print(e)
  606. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  607. def getCountryList(self, request_dict, response):
  608. try:
  609. country_qs = CountryModel.objects.all().values_list('country_name', flat=True)
  610. return response.json(0, list(country_qs))
  611. except Exception as e:
  612. print(e)
  613. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  614. @classmethod
  615. def device_auto_update(cls, user_id, request_dict, response):
  616. verId = request_dict.get('verId', None)
  617. if not verId:
  618. return response.json(444)
  619. LOGGER.info(f'版本ID:{verId},操作用户{user_id}')
  620. version_qs = Equipment_Version.objects.filter(eid=verId, auto_update=True, status=1)
  621. if not version_qs.exists():
  622. return response.json(173)
  623. agent_thread = threading.Thread(
  624. target=VersionManagement().device_async_update,
  625. args=(version_qs.first(),) # 取单个对象
  626. )
  627. agent_thread.start()
  628. return response.json(0)
  629. @staticmethod
  630. def device_async_update(version_qs):
  631. code = version_qs.code
  632. version = version_qs.softwareVersion
  633. ver_data = version_qs.data_json
  634. uid_set_qs = UidSetModel.objects.filter(ucode=code).exclude(version=version) \
  635. .values('uid', 'ip', 'version')
  636. LOGGER.info(f'通知设备自动升级查询符合数量{uid_set_qs.count()}')
  637. if not uid_set_qs.exists():
  638. return
  639. try:
  640. # 创建分页器,每页100条数据
  641. paginator = Paginator(uid_set_qs, 100)
  642. # 遍历每一页数据
  643. for page_num in range(1, paginator.num_pages + 1):
  644. # 获取当前页的数据
  645. page_data = paginator.page(page_num)
  646. # 遍历当前页的每一条数据
  647. for data in page_data:
  648. uid = data['uid']
  649. result = VersionManagement.check_version_auto_update(uid, '', ver_data)
  650. if not result:
  651. LOGGER.info(f'{uid}判断是否符合自动升级:{result}')
  652. continue
  653. serial_number = CommonService.get_serial_number_by_uid(uid)
  654. now_ver = data['version']
  655. # 将版本号带V字符换成空
  656. now_ver_clean = now_ver.replace("V", "")
  657. # 采用packaging模块中的Version类进行版本号比较
  658. now_version = pacVer.Version(now_ver_clean)
  659. new_version = pacVer.Version(version)
  660. if new_version > now_version: # 新版本大于当前设备版本执行MQTT发送升级
  661. VersionManagement.send_auto_update_url(version_qs, uid, serial_number, code, now_ver)
  662. LOGGER.info(f'uid={uid},ucode={code},当前版本{now_ver},最新版本{version}')
  663. except Exception as e:
  664. LOGGER.error(f'异步自动升级异常:ucode:{code},error:{repr(e)}')
  665. @classmethod
  666. def check_version_auto_update(cls, uid, user_id, ver_data):
  667. """
  668. :param uid: 设备UID
  669. :param user_id: 用户id
  670. :param ver_data: 版本指定升级数据
  671. :return: True | False
  672. """
  673. try:
  674. if not ver_data: # 过滤值默认当前版本所有设备自动升级
  675. return True
  676. if uid and ver_data['uid_list']: # 当前版本指定UID
  677. return uid in ver_data['uid_list']
  678. if user_id and ver_data['country_list'] and CONFIG_INFO not in [CONFIG_CN, CONFIG_TEST]: # 当前版本指定用户国家
  679. user_qs = Device_User.objects.filter(userID=user_id).values('region_country')
  680. if not user_qs.exists(): # 用户不存在不升级
  681. return False
  682. if user_qs[0]['region_country'] == 0: # 用户未选择国家 不进行升级提示
  683. return False
  684. return user_qs[0]['region_country'] in ver_data['country_list']
  685. if CONFIG_INFO in [CONFIG_CN, CONFIG_TEST] and ver_data['addr']: # 中国区可指定城市
  686. city_list = ver_data['addr']['city_list']
  687. if not city_list:
  688. return True
  689. uid_set_qs = UidSetModel.objects.filter(uid=uid).values('ip')
  690. if not uid_set_qs:
  691. return False
  692. ip_qs = IPAddr.objects.filter(ip=uid_set_qs[0]['ip']).values('city').order_by('-id')
  693. if not ip_qs:
  694. return False
  695. return ip_qs[0]['city'] in city_list
  696. return False
  697. except Exception as e:
  698. LOGGER.error(f'检测是否符合自动升级{repr(e)}')
  699. return False
  700. @staticmethod
  701. def send_auto_update_url(version_qs, uid, serial_number, code, now_ver):
  702. """
  703. 发送自动升级URL
  704. @param version_qs: 最新版本querySet
  705. @param uid: 设备UID
  706. @param serial_number: 设备序列号
  707. @param code: 设备规格码
  708. @param now_ver: 设备当前版本好
  709. @return:
  710. """
  711. try:
  712. file_path = version_qs.filePath
  713. version = version_qs.version
  714. mci = version_qs.mci
  715. ver = version_qs.softwareVersion
  716. max_ver = version_qs.max_ver
  717. if ver <= max_ver:
  718. user_qs = Device_Info.objects.filter(UID=uid, isShare=False).values('userID_id')
  719. if not user_qs.exists():
  720. LOGGER.info(f'{uid}未添加该设备返回不发MQTT')
  721. return False
  722. user_id = user_qs[0]['userID_id']
  723. # 创建url的token
  724. param_url = "ansjer/" + CommonService.RandomStr(6) + "/" + file_path
  725. data = {'Url': param_url, 'user_id': user_id,
  726. 'uid': uid, 'serial_number': serial_number, 'old_version': "V" + now_ver + "." + code,
  727. 'new_version': version, 'mci': mci}
  728. device_info_value = json.dumps(data)
  729. expire = 600
  730. str_uuid = str(user_id)
  731. if serial_number and serial_number != 'null':
  732. str_uuid += serial_number
  733. elif uid and uid != 'null':
  734. str_uuid += uid
  735. str_uuid += now_ver
  736. device_info_key = 'ASJ:SERVER:VERSION:{}'.format(str_uuid)
  737. LOGGER.info('缓存key={}'.format(device_info_key))
  738. redisObject = RedisObject()
  739. redisObject.set_data(device_info_key, device_info_value, expire)
  740. url_tko = UrlTokenObject()
  741. file_path = url_tko.generate(data={'uid': str_uuid})
  742. url = SERVER_DOMAIN + 'dlotapack/' + file_path
  743. # 主题名称
  744. topic_name = f'ansjer/generic/{serial_number}'
  745. # 发布消息内容
  746. msg = f'{{"commandCode":1,"data":{{"url":"{url}"}}}}'
  747. result = VersionManagement.publish_to_aws_iot_mqtt(serial_number, topic_name, msg)
  748. LOGGER.info(f'uid={uid}发送数据msg={msg},发送MQTT结果={result}')
  749. return True
  750. return False
  751. except Exception as e:
  752. LOGGER.error(f'自动升级异常{repr(e)}')
  753. return False
  754. @staticmethod
  755. def publish_to_aws_iot_mqtt(identification_code, topic_name, msg, qos=1):
  756. """
  757. 发布消息到AWS IoT MQTT(仅尝试一次,无重试)
  758. @param identification_code: 标识码
  759. @param topic_name: 主题名
  760. @param msg: 消息内容(JSON字符串)
  761. @param qos: QoS等级(0或1)
  762. @return: 成功返回True,失败返回False
  763. """
  764. # 入参校验
  765. if not isinstance(identification_code, str) or not identification_code.strip():
  766. LOGGER.error("标识码为空或无效")
  767. return False
  768. if not isinstance(topic_name, str) or not topic_name.strip():
  769. LOGGER.error("主题名为空或无效")
  770. return False
  771. if qos not in (0, 1):
  772. LOGGER.warning("QoS不合法,默认使用1")
  773. qos = 1
  774. # 生成ThingName
  775. thing_name = f'LC_{identification_code}' if identification_code.endswith(
  776. '11L') else f'Ansjer_Device_{identification_code}'
  777. try:
  778. # 查询设备信息
  779. iot_device = iotdeviceInfoModel.objects.filter(thing_name=thing_name).values('endpoint',
  780. 'token_iot_number').first()
  781. if not iot_device:
  782. LOGGER.error(f"未查询到设备信息:{thing_name}")
  783. return False
  784. endpoint = iot_device.get('endpoint', '').strip()
  785. token = iot_device.get('token_iot_number', '').strip()
  786. if not endpoint or not token:
  787. LOGGER.error("设备信息不完整(endpoint或token缺失)")
  788. return False
  789. # 构造请求
  790. encoded_topic = requests.utils.quote(topic_name, safe='')
  791. request_url = f"https://{endpoint}/topics/{encoded_topic}?qos={qos}"
  792. signature = CommonService.rsa_sign(token)
  793. if not signature:
  794. LOGGER.error("Token签名失败")
  795. return False
  796. headers = {
  797. 'x-amz-customauthorizer-name': 'Ansjer_Iot_Auth',
  798. 'Token': token,
  799. 'x-amz-customauthorizer-signature': signature
  800. }
  801. # 发送请求(仅一次)
  802. response = requests.post(
  803. url=request_url,
  804. headers=headers,
  805. data=msg,
  806. timeout=10 # 10秒超时
  807. )
  808. # 结果判断
  809. if response.status_code == 200:
  810. res_json = response.json()
  811. if res_json.get('message') == 'OK':
  812. LOGGER.info(f"发布成功:{topic_name}")
  813. return True
  814. LOGGER.error(f"响应异常:{res_json}")
  815. else:
  816. LOGGER.error(f"请求失败,状态码:{response.status_code}")
  817. return False
  818. except Exception as e:
  819. LOGGER.error(f"发布失败:{str(e)}")
  820. return False