Nav apraksta

tourguidegroupuser_views.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. # -*- coding: utf-8 -*-
  2. from __future__ import division
  3. import json
  4. from django.conf import settings
  5. from django.db import transaction
  6. from logit import logit
  7. from TimeConvert import TimeConvert as tc
  8. from account.models import UserInfo
  9. from group.models import GroupInfo, GroupUserInfo
  10. from utils.admin_utils import is_group_subadmin
  11. from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, UserStatusCode
  12. from utils.error.response_utils import response
  13. from utils.group_photo_utils import get_current_photos
  14. from utils.redis.connect import r
  15. from utils.redis.rgroup import get_group_info, get_group_users_info, get_group_users_kv_info, set_group_users_info
  16. from utils.redis.rkeys import (GROUP_LAST_PHOTO_PK, GROUP_USERS_DELETED_SET, GROUP_USERS_PASSED_SET,
  17. GROUP_USERS_QUIT_SET, GROUP_USERS_REFUSED_SET, TOUR_GUIDE_GROUP_CUR_GATHER_INFO,
  18. TOUR_GUIDE_GROUP_CUR_SESSION, TOUR_GUIDE_GROUP_GEO_INFO, TOUR_GUIDE_GROUP_GEO_SUBMIT_DT,
  19. TOUR_GUIDE_GROUP_USER_GEO_LIST)
  20. from utils.redis.rtourguide import get_tour_guide_own_group
  21. from utils.redis.rtouruser import set_tour_user_belong_group
  22. @logit
  23. def tgu_group_user_is_joined_api(request):
  24. """ 旅行团成员是否已加团 """
  25. admin_id = request.POST.get('admin_id', '') # 导游唯一标识,识别二维码获取
  26. user_id = request.POST.get('user_id', '')
  27. # 获取旅行团唯一标识
  28. group_id = get_tour_guide_own_group(admin_id)
  29. # 用户校验
  30. try:
  31. user = UserInfo.objects.get(user_id=user_id)
  32. except UserInfo.DoesNotExist:
  33. return response(UserStatusCode.USER_NOT_FOUND)
  34. # 群组校验
  35. try:
  36. group = GroupInfo.objects.get(group_id=group_id)
  37. except GroupInfo.DoesNotExist:
  38. return response(GroupStatusCode.GROUP_NOT_FOUND)
  39. # 群组锁定校验
  40. if group.group_lock:
  41. return response(GroupStatusCode.GROUP_HAS_LOCKED)
  42. # Check whether ended
  43. ended_at = group.ended_at
  44. if ended_at and tc.utc_datetime() > (tc.utc_string_to_utc_datetime(ended_at, format='%Y-%m-%dT%H:%M:%SZ') if isinstance(ended_at, basestring) else ended_at):
  45. return response(GroupStatusCode.GROUP_HAS_ENDED)
  46. # 群组用户是否存在
  47. joined = GroupUserInfo.objects.filter(group_id=group_id, user_id=user_id).exists()
  48. return response(200, 'Tour Guide User Has Joined', u'旅行团成员已加团', {
  49. 'joined': joined,
  50. 'group': get_group_info(group_id),
  51. })
  52. @logit(res=settings.LOGIT_RES_FLAG)
  53. def tgu_group_user_join_api(request):
  54. """ 旅行团成员加团 """
  55. admin_id = request.POST.get('admin_id', '') # 导游唯一标识,识别二维码获取
  56. user_id = request.POST.get('user_id', '')
  57. nickname = request.POST.get('nickname', '')
  58. name = request.POST.get('name', '')
  59. phone = request.POST.get('phone', '')
  60. relative_persons = int(request.POST.get('relative_persons', 1))
  61. authority = bool(int(request.POST.get('authority', 1)))
  62. remark = request.POST.get('remark', '')
  63. # 获取旅行团唯一标识
  64. group_id = get_tour_guide_own_group(admin_id)
  65. # 用户校验
  66. try:
  67. user = UserInfo.objects.get(user_id=user_id)
  68. except UserInfo.DoesNotExist:
  69. return response(UserStatusCode.USER_NOT_FOUND)
  70. # 群组校验
  71. try:
  72. group = GroupInfo.objects.get(group_id=group_id)
  73. except GroupInfo.DoesNotExist:
  74. return response(GroupStatusCode.GROUP_NOT_FOUND)
  75. # 群组锁定校验
  76. if group.group_lock:
  77. return response(GroupStatusCode.GROUP_HAS_LOCKED)
  78. # Check whether ended
  79. ended_at = group.ended_at
  80. if ended_at and tc.utc_datetime() > (tc.utc_string_to_utc_datetime(ended_at, format='%Y-%m-%dT%H:%M:%SZ') if isinstance(ended_at, basestring) else ended_at):
  81. return response(GroupStatusCode.GROUP_HAS_ENDED)
  82. # 群组用户记录创建,若记录不存在,则创建,若记录已存在,则更新
  83. group_user, created = GroupUserInfo.objects.get_or_create(
  84. group_id=group_id,
  85. user_id=user_id,
  86. defaults={
  87. 'name': name,
  88. 'phone': phone,
  89. 'relative_persons': relative_persons,
  90. 'authority': authority,
  91. 'remark': remark,
  92. }
  93. )
  94. if not created:
  95. group_user.name = name
  96. group_user.phone = phone
  97. group_user.relative_persons = relative_persons
  98. group_user.authority = authority
  99. group_user.remark = remark
  100. group_user.save()
  101. if group_user.user_status != GroupUserInfo.PASSED:
  102. group_user.current_id = int(r.get(GROUP_LAST_PHOTO_PK % group_id) or -1)
  103. group_user.nickname = nickname or user.final_nickname
  104. group_user.avatar = user.avatar
  105. # group_user.admin = False # Admin Field Default False, Should Not Assign
  106. group_user.user_status = GroupUserInfo.PASSED
  107. group_user.passed_at = tc.utc_datetime()
  108. group_user.save()
  109. # Redis 群组用户数据缓存
  110. set_group_users_info(group)
  111. # Redis 群组通过集合缓存
  112. r.srem(GROUP_USERS_REFUSED_SET % group_id, user_id)
  113. r.srem(GROUP_USERS_DELETED_SET % group_id, user_id)
  114. r.srem(GROUP_USERS_QUIT_SET % group_id, user_id)
  115. r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id)
  116. curinfo = get_current_photos(group_id, user_id, group_user.current_id, request=request)
  117. # 添加默认地理位置信息
  118. r.geoadd(TOUR_GUIDE_GROUP_GEO_INFO % group_id, 0, 0, user_id)
  119. # 设置旅行团成员所属的旅行团
  120. set_tour_user_belong_group(user_id, group_id)
  121. return response(200, 'Tour Guide User Join Success', u'旅行团成员加团成功', {
  122. 'current_id': curinfo.get('current_id', ''),
  123. 'photos': curinfo.get('photos', ''),
  124. 'group_id': group_id,
  125. 'group': get_group_info(group_id),
  126. 'user_id': user_id,
  127. 'users': get_group_users_info(group_id, user_id),
  128. })
  129. @logit
  130. def tgu_group_user_remove_api(request):
  131. """ 旅行团成员移除,管理员主动,团成员被动 """
  132. group_id = request.POST.get('group_id', '')
  133. admin_id = request.POST.get('admin_id', '') # 导游唯一标识
  134. user_id = request.POST.get('user_id', '')
  135. # 群组校验
  136. try:
  137. group = GroupInfo.objects.get(group_id=group_id)
  138. except GroupInfo.DoesNotExist:
  139. return response(GroupStatusCode.GROUP_NOT_FOUND)
  140. # 权限校验
  141. if not is_group_subadmin(group_id, admin_id):
  142. return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
  143. # 管理员也不允许将自己移除
  144. if admin_id == user_id:
  145. return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF)
  146. # 群组用户校验
  147. try:
  148. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, status=True)
  149. except GroupUserInfo.DoesNotExist:
  150. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  151. # 群组用户移除
  152. group_user.user_status = GroupUserInfo.DELETED
  153. group_user.deleted_at = tc.utc_datetime()
  154. group_user.save()
  155. # Redis 群组数据缓存更新
  156. group_users = set_group_users_info(group)
  157. # Redis 群组删除集合缓存
  158. r.srem(GROUP_USERS_PASSED_SET % group_id, user_id)
  159. r.sadd(GROUP_USERS_DELETED_SET % group_id, user_id)
  160. # 移除地理位置信息
  161. r.georem(TOUR_GUIDE_GROUP_GEO_INFO % group_id, user_id)
  162. return response(200, 'Tour Guide User Remove Success', u'旅行团成员移除成功', {
  163. 'group_id': group_id,
  164. 'users': group_users,
  165. })
  166. @logit
  167. @transaction.atomic
  168. def tgu_group_user_update_api(request):
  169. """ 旅行团成员信息更新 """
  170. group_id = request.POST.get('group_id', '')
  171. admin_id = request.POST.get('admin_id', '') # 导游唯一标识
  172. user_id = request.POST.get('user_id', '')
  173. name = request.POST.get('name', '')
  174. phone = request.POST.get('phone', '')
  175. relative_persons = int(request.POST.get('relative_persons', 0))
  176. authority = bool(int(request.POST.get('authority', 0)))
  177. remark = request.POST.get('remark', '')
  178. # 群组校验
  179. try:
  180. group = GroupInfo.objects.get(group_id=group_id)
  181. except GroupInfo.DoesNotExist:
  182. return response(GroupStatusCode.GROUP_NOT_FOUND)
  183. # 权限校验
  184. if admin_id:
  185. if not is_group_subadmin(group_id, admin_id):
  186. return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
  187. else:
  188. if not GroupUserInfo.objects.filter(group_id=group_id, user_id=user_id, status=True).exists():
  189. return response(GroupStatusCode.NOT_GROUP_ADMIN)
  190. # 权限
  191. try:
  192. group_user = GroupUserInfo.objects.select_for_update().get(group_id=group_id, user_id=user_id, status=True)
  193. except GroupUserInfo.DoesNotExist:
  194. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  195. # 用户信息更新
  196. # TODO: Whether sync name and phone to UserInfo or not?
  197. if name:
  198. group_user.name = name
  199. if phone:
  200. group_user.phone = phone
  201. if relative_persons:
  202. # TODO & UNDO: Should check not gt GroupInfo.total_persons & App remind
  203. group_user.relative_persons = relative_persons
  204. if authority:
  205. group_user.authority = authority
  206. if remark:
  207. group_user.remark = remark
  208. group_user.save()
  209. # Redis 群组用户数据缓存
  210. group_users = set_group_users_info(group)
  211. return response(200, 'Tour Guide User Update Success', u'旅行团成员信息更新成功', {
  212. 'group_id': group_id,
  213. 'group': group.data,
  214. 'users': group_users,
  215. })
  216. def get_geo_submit_flag(geo_at, gather_at):
  217. """ 是否上传过位置字段(即是否失联) """
  218. if geo_at and gather_at:
  219. geo_at = tc.utc_string_to_utc_datetime(geo_at, format='%Y-%m-%dT%H:%M:%SZ')
  220. gather_at = tc.utc_string_to_utc_datetime(gather_at, format='%Y-%m-%dT%H:%M:%SZ')
  221. current_dt = tc.utc_datetime()
  222. delta_seconds = tc.total_seconds(gather_at - current_dt)
  223. # 距离集合时间超过30分钟是5分钟,15分钟到30分钟是3分钟,15分钟以内是1分钟
  224. for delta, gdt in [(1800, 300), (900, 180), (0, 60)]:
  225. if delta_seconds > delta:
  226. return tc.total_seconds(current_dt - geo_at) <= gdt
  227. return False
  228. @logit
  229. def tgu_group_user_locations_api(request):
  230. """ 旅行团所有成员位置信息 """
  231. group_id = request.POST.get('group_id', '')
  232. admin_id = request.POST.get('admin_id', '') # 导游唯一标识
  233. # 权限校验
  234. if not is_group_subadmin(group_id, admin_id):
  235. return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
  236. # 获取集合经纬度
  237. gather_info = json.loads(r.get(TOUR_GUIDE_GROUP_CUR_GATHER_INFO % group_id) or '{}')
  238. # GEO submit dts
  239. geo_dts = r.hgetall(TOUR_GUIDE_GROUP_GEO_SUBMIT_DT % group_id)
  240. # [['x', 0.33, (2.68220901489e-06, 1.26736058093e-06)], []]
  241. locations = r.georadius(TOUR_GUIDE_GROUP_GEO_INFO % group_id, gather_info.get('gather_lon', 0), gather_info.get('gather_lat', 0), '+inf', unit='m', withdist=True, withcoord=True, sort='ASC')
  242. # [{'lon': 2.68220901489e-06, 'lat': 26736058093e-06, 'dist': 0.33, etc...}, {}]
  243. # 获取旅行团用户 KV 信息
  244. group_users_kv_info = get_group_users_kv_info(group_id)
  245. locations = [dict(group_users_kv_info[loc[0]], **{
  246. 'lon': loc[2][0],
  247. 'lat': loc[2][1],
  248. 'dist': loc[1],
  249. 'geo_submited': get_geo_submit_flag(geo_dts.get(loc[0], ''), gather_info.get('gather_at', '')),
  250. }) for loc in locations]
  251. return response(200, 'Get Tour Guide Group All User Location Success', u'获取旅行团成员地理位置信息成功', {
  252. 'group_id': group_id,
  253. 'locations': locations,
  254. })
  255. @logit
  256. def tgu_group_user_location_api(request):
  257. """ 旅行团单个成员位置信息 """
  258. group_id = request.POST.get('group_id', '')
  259. admin_id = request.POST.get('admin_id', '') # 导游唯一标识
  260. user_id = request.POST.get('user_id', '')
  261. # 权限校验
  262. if not is_group_subadmin(group_id, admin_id):
  263. return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
  264. session_id = r.get(TOUR_GUIDE_GROUP_CUR_SESSION % group_id)
  265. locations = r.lrange(TOUR_GUIDE_GROUP_USER_GEO_LIST % (group_id, session_id, user_id), 0, -1)
  266. return response(200, 'Get Tour Guide Group User Location Success', u'获取旅行团成员地理位置信息成功', {
  267. 'group_id': group_id,
  268. 'user_id': user_id,
  269. 'locations': [json.loads(loc) for loc in locations]
  270. })