utils.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import base64
  4. import logging
  5. import math
  6. import itsdangerous
  7. from functools import wraps
  8. import simplejson as json
  9. from Crypto.Cipher import AES
  10. from django.conf import settings
  11. from django.contrib.auth.hashers import check_password
  12. from django.core.handlers.wsgi import WSGIRequest
  13. from django.http import JsonResponse
  14. from django.utils.encoding import force_text
  15. from mongoengine import NotUniqueError, DoesNotExist
  16. from typing import TYPE_CHECKING
  17. from apilib.utils_string import md5
  18. from apps.web.agent.models import Agent
  19. from apps.web.api.exceptions import ApiException, ApiAuthException
  20. from apps.web.core.exceptions import EmptyInput, InvalidParameter
  21. from apps.web.dealer.models import Dealer
  22. from apps.web.constant import ErrorCode
  23. from apps.web.core.utils import JsonErrorResponse
  24. from apps.web.device.models import Device
  25. if TYPE_CHECKING:
  26. pass
  27. logger = logging.getLogger(__name__)
  28. def api_dealer_auth(request):
  29. # type: (WSGIRequest)->Dealer
  30. """
  31. 经销商授权
  32. :param request:
  33. :return:
  34. """
  35. if request is None:
  36. raise ApiAuthException(errmsg = u'请确认传入授权头')
  37. if 'HTTP_AUTHORIZATION' not in request.META:
  38. logger.debug('http header not found')
  39. raise ApiAuthException(errmsg = u'请确认传入授权头')
  40. try:
  41. credentials = request.META['HTTP_AUTHORIZATION'].split()[1]
  42. except IndexError:
  43. raise ApiAuthException(errmsg = u'请确认授权头的格式符合规范')
  44. auth = base64.b64decode(credentials)
  45. username, password = auth.split(":")[0], auth.split(":")[1]
  46. sign = request.META.get('HTTP_SIGN')
  47. if sign is None:
  48. payload = json.loads(request.body) if request.body else {}
  49. if not payload or 'sign' not in payload:
  50. raise ApiAuthException(errmsg = u'找不到签名')
  51. sign = payload['sign']
  52. logger.debug('api = {}; username = {}; sign = {}'.format(str(request.path), username, sign))
  53. agent = Agent.objects(agentSign = sign).first()
  54. if not agent:
  55. raise ApiAuthException(errmsg = u'找不到代理商')
  56. dealer = Dealer.objects(username = username, agentId = str(agent.id)).first()
  57. if dealer is None:
  58. logger.debug('dealer not found')
  59. raise ApiAuthException(errmsg = u'找不到经销商')
  60. if not (check_password(md5(password), dealer.password) or check_password(password, dealer.password)):
  61. logger.debug('dealer password does not match')
  62. raise ApiAuthException(errmsg = u'经销商账号名或者密码错误')
  63. setattr(dealer, 'api_conf', {
  64. 'agentId': str(agent.id),
  65. 'agentSign': sign,
  66. 'mySign': agent.mySign,
  67. 'domain': agent.domain
  68. })
  69. return dealer
  70. def api_call(nil = None, logger = None, *accepted_exceptions):
  71. logger = logging.getLogger(__name__) if logger is None else logger
  72. exc_handler_map = {
  73. TypeError: u'类型错误',
  74. EmptyInput: u'空的输入',
  75. NotUniqueError: u'对象已存在',
  76. DoesNotExist: u'对象不存在',
  77. InvalidParameter: u'参数不合法'
  78. }
  79. def decorator(func):
  80. @wraps(func)
  81. def wrapper(request, *args, **kwargs):
  82. _accepted_exceptions = accepted_exceptions
  83. _accepted_exceptions = (Exception,) if not len(_accepted_exceptions) else _accepted_exceptions
  84. try:
  85. dealer = api_dealer_auth(request)
  86. try:
  87. logger.debug('enter {}'.format(str(request.path)))
  88. return func(request, dealer, *args, **kwargs)
  89. finally:
  90. logger.debug('left {}'.format(str(request.path)))
  91. except ApiException as e:
  92. logger.error(str(e))
  93. return e.to_response()
  94. except _accepted_exceptions as e:
  95. if request.FILES:
  96. logger.error('[error_tolerate]: view({func_name}) error occurred when uploading files'
  97. .format(func_name = func.__name__))
  98. logger.exception(e)
  99. else:
  100. logger.exception(
  101. u'[error_tolerate] view({func_name}) caught an error,'
  102. u'(error={error}) (request=(body={request_body},REQUEST={request_request}))'
  103. .format(func_name = func.__name__, error = force_text(e.message),
  104. request_body = force_text(request.body),
  105. request_request = force_text(request.REQUEST)))
  106. if callable(nil):
  107. def get_arg_count(callable_):
  108. code = getattr(callable_, '__code__', None)
  109. if code:
  110. return code.co_argcount
  111. exc_type = type(e)
  112. if get_arg_count(nil) == 1:
  113. #: 只处理自定义的exceptions,避免暴露python的其他错误
  114. if exc_type in exc_handler_map:
  115. #: 优先返回更详细的报错信息, 无法找到就返回默认的
  116. return nil(next(iter(e.args), exc_handler_map[exc_type]))
  117. else:
  118. return nil(u'系统错误')
  119. else:
  120. return nil()
  121. else:
  122. return nil or api_exception_response()
  123. return wrapper
  124. return decorator
  125. deprecated_api_error_response = JsonErrorResponse
  126. def api_ok_response(payload = {}):
  127. response_dict = {
  128. 'errcode': ErrorCode.SUCCESS,
  129. 'errmsg': 'SUCCESS',
  130. 'result': 1,
  131. 'payload': payload,
  132. 'description': ''
  133. }
  134. response_dict.update(payload)
  135. return JsonResponse(response_dict)
  136. def api_ok_response_v2(**data):
  137. response_dict = {
  138. 'errcode': ErrorCode.SUCCESS,
  139. 'errmsg': 'SUCCESS'
  140. }
  141. response_dict.update(**data)
  142. return JsonResponse(response_dict)
  143. def api_error_response(errcode, errmsg, payload = {}):
  144. response_dict = {
  145. 'errcode': errcode,
  146. 'errmsg': errmsg,
  147. 'result': 0,
  148. 'description': errmsg,
  149. 'payload': payload
  150. }
  151. return JsonResponse(response_dict)
  152. def api_exception_response(payload = {}):
  153. response_dict = {
  154. 'errcode': ErrorCode.API_EXCEPTION,
  155. 'errmsg': u'系统错误',
  156. 'result': 0,
  157. 'description': u'系统错误',
  158. 'payload': payload
  159. }
  160. return JsonResponse(response_dict)
  161. def AES_CBC_PKCS5padding_encrypt(s, dataSecret=None, dataSecretIV=None): # type:(str, str, str) -> str
  162. """
  163. AES CBC PKCS5padding 加密
  164. :param s: 待加密字符串
  165. :param dataSecret: 加密秘钥
  166. :param dataSecretIV: 加密向量
  167. """
  168. _mode = AES.MODE_CBC
  169. _size = AES.block_size
  170. _secret = str(dataSecret) if dataSecret else str(settings.AES_CBC_DATA_SECRET)
  171. _secretIV = str(dataSecretIV) if dataSecretIV else str(settings.AES_CBC_DATA_SECRET_IV)
  172. pad = lambda x: x + (_size - len(s) % _size) * chr(_size - len(s) % _size)
  173. cipher = AES.new(_secret, _mode, _secretIV)
  174. crypt = cipher.encrypt(pad(s))
  175. return base64.b64encode(crypt)
  176. def AES_CBC_PKCS5padding_decrypt(s, dataSecret=None, dataSecretIV=None):
  177. """
  178. AES CBC PKCS5padding 解密
  179. :param s: 待加密字符串
  180. :param dataSecret: 加密秘钥
  181. :param dataSecretIV: 加密向量
  182. """
  183. _mode = AES.MODE_CBC
  184. _size = AES.block_size
  185. _secret = str(dataSecret) if dataSecret else str(settings.AES_CBC_DATA_SECRET)
  186. _secretIV = str(dataSecretIV) if dataSecretIV else str(settings.AES_CBC_DATA_SECRET_IV)
  187. enc = base64.b64decode(s)
  188. unpad = lambda x: x[0:-ord(x[-1])]
  189. cipher = AES.new(_secret, _mode, _secretIV)
  190. return unpad(cipher.decrypt(enc))
  191. def generate_json_token(data, expire=None):
  192. salt = settings.SHAN_DONG_TOKEN_SECRET
  193. its = itsdangerous.TimedJSONWebSignatureSerializer(salt, expire)
  194. return its.dumps(data)
  195. def parse_json_token(s, expire=None):
  196. salt = settings.SHAN_DONG_TOKEN_SECRET
  197. its = itsdangerous.TimedJSONWebSignatureSerializer(salt, expire)
  198. try:
  199. result = its.loads(s)
  200. except itsdangerous.BadData:
  201. return dict()
  202. return result
  203. def bd09_to_gcj02(lng, lat):
  204. """
  205. 百度坐标系到google坐标系的经纬度转换
  206. :param lng: 百度经度
  207. :param lat: 百度维度
  208. :return:
  209. """
  210. if lng == 0.0 or lat == 0.0:
  211. return lng, lat
  212. x_pi = 3.14159265358979324 * 3000.0 / 180.0
  213. x = lng - 0.0065
  214. y = lat - 0.006
  215. z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
  216. theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
  217. gg_lng = z * math.cos(theta)
  218. gg_lat = z * math.sin(theta)
  219. return [gg_lng, gg_lat]
  220. def get_coordinates_and_nums(groupId):
  221. devices = Device.objects.filter(groupId=groupId)
  222. _count = devices.count()
  223. if _count == 0:
  224. return 0.0, 0.0, _count
  225. for dev in devices:
  226. if dev.location is not None and dev.location.has_key('coordinates'):
  227. coord = dev.location['coordinates']
  228. return coord[0], coord[1], _count
  229. return 0.0, 0.0, _count