FAQController.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import json
  4. import os
  5. import shutil
  6. import time
  7. import traceback
  8. from django.core import serializers
  9. from django.db import models
  10. from django.http import HttpResponse
  11. from django.utils.decorators import method_decorator
  12. from django.views.decorators.csrf import csrf_exempt
  13. from django.views.generic.base import View
  14. import Ansjer
  15. from Ansjer.config import BASE_DIR, SERVER_TYPE, SERVER_DOMAIN, SERVER_DOMAIN_SSL
  16. from Model.models import FAQModel, HelpLink
  17. from Object.Enums.RedisKeyConstant import RedisKeyConstant
  18. from Object.RedisObject import RedisObject
  19. from Object.ResponseObject import ResponseObject
  20. from Object.TokenObject import TokenObject
  21. from var_dump import var_dump
  22. from Ansjer.config import LOGGER
  23. from Service.CommonService import CommonService
  24. from Service.ModelService import ModelService, ZositechHelpModel
  25. class FAQUploadView(View):
  26. @method_decorator(csrf_exempt)
  27. def dispatch(self, request, *args, **kwargs):
  28. return super(FAQUploadView, self).dispatch(request, *args, **kwargs)
  29. def get(self, request, *args, **kwargs):
  30. request.encoding = 'utf-8'
  31. request_dict = request.GET
  32. fileName = request.FILES.get('fileName', None)
  33. return self.validate(fileName, request_dict)
  34. def post(self, request, *args, **kwargs):
  35. request.encoding = 'utf-8'
  36. request_dict = request.POST
  37. fileName = request.FILES.get('fileName', None)
  38. return self.validate(fileName, request_dict)
  39. def validate(self, fileName, request_dict):
  40. token = TokenObject(request_dict.get('token', None))
  41. response = ResponseObject()
  42. if token.code != 0:
  43. return response.json(token.code)
  44. own_permission = ModelService.check_perm(userID=token.userID, permID=120)
  45. if own_permission is not True:
  46. return response.json(404)
  47. try:
  48. redisObject = RedisObject()
  49. path = '/'.join((BASE_DIR, 'static/FAQImages/tmp')).replace('\\', '/') + '/'
  50. # path = '/'.join((BASE_DIR, 'static/{user}/FAQImages'.format(user=token.userID))).replace('\\', '/') + '/'
  51. if not os.path.exists(path):
  52. os.makedirs(path)
  53. # 先从redis中取出token对应的图片信息
  54. images = redisObject.get_data(key=token.token)
  55. if images is not False:
  56. images = json.loads(images)
  57. # 判断此次编辑是否已经存在对应的图片
  58. if images.__contains__(str(fileName)):
  59. file_name = images[str(fileName)]
  60. index = file_name.find('static/')
  61. filePath = file_name[index:]
  62. if SERVER_TYPE == "Ansjer.formal_settings":
  63. filePath = SERVER_DOMAIN+'faq/image/' + filePath
  64. else:
  65. filePath = SERVER_DOMAIN_SSL+'faq/image/' + filePath
  66. return response.json(0, {'filePath': filePath})
  67. # redis中没有对应的图片信息
  68. tmp_name = str(fileName)
  69. suffix = tmp_name[tmp_name.find('.'):]
  70. tmp_file_name = int(time.time())
  71. tmp_file_name = '{file_name}{suffix}'.format(file_name=tmp_file_name, suffix=suffix)
  72. file_name = path + str(tmp_file_name)
  73. if os.path.exists(file_name):
  74. os.remove(file_name)
  75. destination = open(file_name, 'wb+')
  76. for chunk in fileName.chunks():
  77. destination.write(chunk)
  78. destination.close()
  79. # 把图片信息保存到redis中
  80. images = redisObject.get_data(token.token)
  81. if images is False:
  82. images = json.dumps({})
  83. images = json.loads(images)
  84. images[tmp_name] = file_name
  85. redisObject.set_data(key=token.token, val=json.dumps(images), expire=3600)
  86. except Exception as e:
  87. errorInfo = traceback.format_exc()
  88. print('上传文件错误: %s' % errorInfo)
  89. return response.json(700, {'details': repr(e)})
  90. else:
  91. index = file_name.find('static/')
  92. filePath = file_name[index:]
  93. if SERVER_TYPE == "Ansjer.formal_settings":
  94. filePath = 'http://www.zositechc.cn/faq/image/' + filePath
  95. else:
  96. filePath = 'http://test.www.zositechc.cn/faq/image/' + filePath
  97. # filePath = "http://192.168.136.35:8000/" + 'faq/image/' + filePath
  98. return response.json(0, {'filePath': filePath})
  99. class getFAQImage(View):
  100. def post(self, request, *args, **kwargs):
  101. request.encoding = 'utf-8'
  102. filePath = kwargs.get('filePath', None)
  103. filePath.encode(encoding='utf-8', errors='strict')
  104. response = ResponseObject()
  105. return self.getFile(filePath, response)
  106. def get(self, request, *args, **kwargs):
  107. request.encoding = 'gb2312'
  108. filePath = kwargs.get('filePath', None)
  109. response = ResponseObject()
  110. filePath.encode(encoding='gb2312', errors='strict')
  111. return self.getFile(filePath, response)
  112. def getFile(self, filePath, response):
  113. if filePath:
  114. pass
  115. else:
  116. return response.json(800)
  117. fullPath = os.path.join(BASE_DIR, filePath).replace('\\', '/')
  118. var_dump(fullPath)
  119. if os.path.isfile(fullPath):
  120. try:
  121. Imagedata = open(fullPath, 'rb').read()
  122. except Exception as e:
  123. return response.json(906, repr(e))
  124. else:
  125. return HttpResponse(Imagedata, content_type="image/jpeg")
  126. else:
  127. return response.json(907)
  128. class FAQView(View):
  129. @method_decorator(csrf_exempt)
  130. def dispatch(self, *args, **kwargs):
  131. return super(FAQView, self).dispatch(*args, **kwargs)
  132. def post(self, request, *args, **kwargs):
  133. request.encoding = 'utf-8'
  134. request_dict = request.POST
  135. operation = kwargs.get('operation', None)
  136. return self.validate(request_dict, operation)
  137. def get(self, request, *args, **kwargs):
  138. request.encoding = 'utf-8'
  139. request_dict = request.GET
  140. operation = kwargs.get('operation', None)
  141. return self.validate(request_dict, operation)
  142. def validate(self, request_dict, operation):
  143. token = TokenObject(request_dict.get('token', None))
  144. response = ResponseObject()
  145. if operation != 'zositechHelp':
  146. if token.code != 0:
  147. return response.json(token.code)
  148. if operation == 'add':
  149. return self.do_add(token, request_dict, response)
  150. elif operation == 'query':
  151. return self.do_query(token.userID, request_dict, response)
  152. elif operation == 'update':
  153. return self.do_update(token, request_dict, response)
  154. elif operation == 'delete':
  155. return self.do_delete(token.userID, request_dict, response)
  156. elif operation == 'zositechHelp':
  157. return self.do_zositechHelp(request_dict, response)
  158. elif operation == 'synZositechHelp':
  159. return self.do_synZositechHelp(request_dict, response)
  160. else:
  161. return response.json(404)
  162. def do_add(self, token, request_dict, response):
  163. own_permission = ModelService.check_perm(userID=token.userID, permID=120)
  164. if own_permission is not True:
  165. return response.json(404)
  166. title = request_dict.get('title', None)
  167. content = request_dict.get('content', None)
  168. if title and content:
  169. try:
  170. # 对content中的图片路径进行修改
  171. content = str(content)
  172. content = content.replace('faq/image/static/FAQImages/tmp', 'faq/image/static/FAQImages')
  173. # 取出redis中保存的此次上传的图片信息
  174. redisObject = RedisObject()
  175. images = redisObject.get_data(key=token.token)
  176. if images is not False:
  177. images = json.loads(images)
  178. # 把图片从临时文件移动到FAQ资源文件夹下
  179. for k, v in images.items():
  180. start_index1 = v.find('tmp/')
  181. start_index2 = start_index1 + 4
  182. new_path = v[0:start_index1] + v[start_index2:]
  183. shutil.move(v, new_path)
  184. now_time = int(time.time())
  185. FAQModel.objects.create(**{
  186. 'title': title,
  187. 'content': content,
  188. 'add_time': now_time,
  189. 'update_time': now_time
  190. })
  191. # 删除redis中token对应的信息
  192. redisObject.del_data(key=token.token)
  193. except Exception as e:
  194. print(e)
  195. return response.json(174)
  196. return response.json(0)
  197. else:
  198. return response.json(444)
  199. def do_query(self, userID, request_dict, response):
  200. page = request_dict.get('page', None)
  201. line = request_dict.get('line', None)
  202. search_key = request_dict.get('search_key', None)
  203. if page and line:
  204. if search_key:
  205. own_permission = ModelService.check_perm(userID=userID, permID=110)
  206. if own_permission is not True:
  207. return response.json(404)
  208. faq_qs = FAQModel.objects.filter(title__contains=search_key).order_by('-add_time')
  209. else:
  210. own_permission = ModelService.check_perm(userID=userID, permID=100)
  211. if own_permission is not True:
  212. return response.json(404)
  213. faq_qs = FAQModel.objects.filter().order_by('-add_time')
  214. if not faq_qs.exists():
  215. return response.json(0, {'count': 0, 'data': []})
  216. count = faq_qs.count()
  217. page = int(page)
  218. line = int(line)
  219. start = (page - 1) * line
  220. end = start + line
  221. faq_qs = faq_qs.values()[start:end]
  222. return response.json(0, {'count': count, 'data': list(faq_qs)})
  223. else:
  224. return response.json(444)
  225. def do_update(self, token, request_dict, response):
  226. own_permission = ModelService.check_perm(userID=token.userID, permID=130)
  227. if own_permission is not True:
  228. return response.json(404)
  229. id = request_dict.get('id', None)
  230. title = request_dict.get('title', None)
  231. content = request_dict.get('content', None)
  232. if id:
  233. now_time = int(time.time())
  234. data = {
  235. 'update_time': now_time
  236. }
  237. if title:
  238. data['title'] = title
  239. if content:
  240. content = str(content)
  241. content = content.replace('faq/image/static/FAQImages/tmp', 'faq/image/static/FAQImages')
  242. # 取出redis中保存的此次上传的图片信息
  243. redisObject = RedisObject()
  244. images = redisObject.get_data(key=token.token)
  245. if images is not False:
  246. images = json.loads(images)
  247. # 把图片从临时文件移动到FAQ资源文件夹下
  248. for k, v in images.items():
  249. start_index1 = v.find('tmp/')
  250. start_index2 = start_index1 + 4
  251. new_path = v[0:start_index1] + v[start_index2:]
  252. shutil.move(v, new_path)
  253. # 删除redis中token对应的信息
  254. redisObject.del_data(key=token.token)
  255. data['content'] = content
  256. FAQModel.objects.filter(id=id).update(**data)
  257. return response.json(0)
  258. else:
  259. return response.json(444)
  260. def do_delete(self, userID, request_dict, response):
  261. own_permission = ModelService.check_perm(userID=userID, permID=140)
  262. if own_permission is not True:
  263. return response.json(404)
  264. id = request_dict.get('id', None)
  265. if id:
  266. try:
  267. faq_qs = FAQModel.objects.filter(id=id)
  268. faq_qs.delete()
  269. except Exception as e:
  270. print(e)
  271. return response.json(173)
  272. else:
  273. return response.json(0)
  274. else:
  275. return response.json(444)
  276. def do_zositechHelp(self, request_dict, response):
  277. locale = request_dict.get('locale', None)
  278. label_names = request_dict.get('label_names', None)
  279. origin = request_dict.get('origin', None)
  280. help_qs = None
  281. if label_names:
  282. help = ZositechHelpModel.objects.filter(locale=locale, label_names__contains=label_names,
  283. origin=origin).values()
  284. else:
  285. help = ZositechHelpModel.objects.filter(locale=locale, origin=origin).values()
  286. if help.exists():
  287. # send_dict = CommonService.qs_to_dict(help)
  288. send_dict = list(help)
  289. return response.json(0, send_dict)
  290. else:
  291. return response.json(444)
  292. def do_synZositechHelp(self, request_dict, response):
  293. zhresults = request_dict.get('zhresults', None).replace("\'", "XX??????XX")
  294. #.replace("\"", "XX??????XX").replace("\'", "\"").replace("XX??????XX", "\'")
  295. zhresults = json.loads(zhresults)
  296. enresults = request_dict.get('enresults', None).replace("\'", "XX??????XX")
  297. enresults = json.loads(enresults)
  298. ZositechHelpModel.objects.all().delete()
  299. for data in zhresults['articles']:
  300. labname = ""
  301. if data['label_names']:
  302. for lab in data['label_names']:
  303. if lab:
  304. labname += ","
  305. labname = lab
  306. if not labname:
  307. labname = None
  308. ZositechHelpModel.objects.create(**{
  309. 'locale': data['locale'],
  310. 'label_names': labname,
  311. 'origin': 'web_widget',
  312. 'content': json.dumps(data).replace("\'", "\"").replace("XX??????XX", "\'")
  313. })
  314. for data in enresults['articles']:
  315. labname = ""
  316. if data['label_names']:
  317. for lab in data['label_names']:
  318. if lab:
  319. labname += ","
  320. labname = lab
  321. if not labname:
  322. labname = None
  323. ZositechHelpModel.objects.create(**{
  324. 'locale': data['locale'],
  325. 'label_names': labname,
  326. 'origin': 'web_widget',
  327. 'content': json.dumps(data).replace("\'", "\"").replace("XX??????XX", "\'")
  328. })
  329. return response.json(0)
  330. class HelpLinkView(View):
  331. def get(self, request, *args, **kwargs):
  332. request.encoding = 'utf-8'
  333. operation = kwargs.get('operation')
  334. return self.validation(request.GET, request, operation)
  335. def post(self, request, *args, **kwargs):
  336. request.encoding = 'utf-8'
  337. operation = kwargs.get('operation')
  338. return self.validation(request.POST, request, operation)
  339. def validation(self, request_dict, request, operation):
  340. response = ResponseObject('en')
  341. tko = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
  342. if tko.code != 0:
  343. return response.json(tko.code)
  344. response.lang = tko.lang
  345. userID = tko.userID
  346. if operation == 'queryFAQByDeviceType': # 获取电池电量列表
  347. return HelpLinkView.query_faq_by_device_type(request, request_dict, response)
  348. else:
  349. return response.json(414)
  350. @staticmethod
  351. def query_faq_by_device_type(request, request_dict, response):
  352. """根据设备类型和语言查询帮助链接"""
  353. device_type = request_dict.get('device_type', None)
  354. # lang = request_dict.get('lang', 'en')
  355. # app_bundle_id = request_dict.get('app_bundle_id', None)
  356. lang = 'en'
  357. if not device_type:
  358. return response.json(444, {'message': 'device_type和lang参数不能为空'})
  359. try:
  360. device_type = int(device_type)
  361. redis = RedisObject()
  362. cache_key = RedisKeyConstant.HELP_LINK_TYPE.value + f'{device_type}:{lang}'
  363. # 先尝试从缓存获取
  364. cached_data = redis.get_data(cache_key)
  365. if cached_data:
  366. cached_data = json.loads(cached_data)
  367. return response.json(0, cached_data)
  368. # 优化数据库查询 - 单次查询获取结果
  369. help_link = HelpLink.objects.filter(
  370. models.Q(device_type=device_type) | models.Q(device_type=-1),
  371. lang=lang,
  372. is_active=True
  373. ).order_by(
  374. models.Case(
  375. models.When(device_type=device_type, then=0),
  376. default=1
  377. )
  378. ).first()
  379. if not help_link:
  380. return response.json(173)
  381. # 构建返回数据
  382. data = {
  383. 'url': help_link.url,
  384. 'title': help_link.title,
  385. 'description': help_link.description
  386. }
  387. # 设置缓存,过期时间30天
  388. try:
  389. redis.set_data(cache_key, json.dumps(data), RedisKeyConstant.EXPIRE_TIME_30_DAYS.value)
  390. except Exception as e:
  391. LOGGER.error(f"设置Redis缓存出错: {repr(e)}")
  392. # 缓存失败不影响主流程
  393. return response.json(0, data)
  394. except Exception as e:
  395. LOGGER.error(f"查询帮助链接出错: {repr(e)}")
  396. return response.json(500)